2016-05-13 2 views
8

У меня есть модальная форма, отображаемая через javascript. Модель называется книга.Render javascript из нескольких мест: Rails way

# controllers/books_controller.rb 

def new 
    @book = Book.new 
end 

def create 
    @book = Book.find(params[:id]) 
    @book.save 
end 

Вместо того, чтобы новые и редактировать HTML, я использую CoffeeScript:

# views/new.js.coffee 

CustomModal.open "<%= j render('books/modal_form', book: @book) %>" 

-

# views/create.js.coffee 

<% if @book.valid? %> 
CustomModal.hide() 
# Other callback scripts for showing alert, etc 
<% else %> 
# Script for showing errors in the modal 
<% end %> 

И ссылки для запуска модальный:

= link_to "Create Book", new_book_path, remote: true 

Теперь проблема заключается в том, что эта ссылка использовалась только на странице списка книг. Таким образом, js callback, когда книга была создана, вызвала предупреждение и обновила список с изменениями.

Теперь я должен добавить эту кнопку на другую страницу, где нет списка, поэтому мне нужен другой обратный вызов (неважно, какие обратные вызовы действительно).

Таким образом, я должен был добавить к create.js.coffee что-то вроде:

# views/create.js.coffee 

<% if @book.valid? %> 
CustomModal.hide() 
# if the list exists 
# show alert 
# update lists 
# else 
# do different things 
# end 
<% else %> 
# Script for showing errors in the modal 
<% end %> 

Кажется, вид грязный, но это не так ужасно. Проблема в том, что теперь у меня более 3 условных выражений, потому что кнопка «Создать книгу» используется несколько раз вдоль веб-приложения.

Итак, любые идеи о шаблоне дизайна для этого?

+0

Мне нравится подход возврата coffeescript. У этого есть хорошее чувство об этом, будучи немного статически динамичным. Когда вы просите «идеи о шаблоне проектирования для этого», что именно вы ищете в ответ? –

+0

Я ищу шаблон, который делает всевозможные возможности легкими для mantain и т. Д. –

+0

Как насчет того, чтобы не возвращать реальный скрипт, а просто вызывать обратный вызов, который может быть определен по-разному на каждой странице, где вам нужна ссылка? Что-то вроде: если обратный вызов определен, вызовите обратный вызов , иначе сделайте материал по умолчанию – michalvalasek

ответ

0

Возможно, вы захотите сохранить логику успеха/ошибки в контроллере и вместо этого использовать отдельные представления на основе успеха/сбоя. Поэтому у вас есть create_success.js.coffee и create_error.js.coffee. Каждый из них управляет своей ситуацией и не заботится о другом. ПРИМЕЧАНИЕ: это psuedo-код.

# controller 
def create 
    @book = Book.find(params[:id]) 

    if @book.save # save will run validations 
    render :create_success 
    else 
    render :create_error 
    end 
end 

# Views 
# 
# create_success.js.coffee 
CustomModal.hide() 
# other stuff you do if successful 


# create_error.js.coffee 
# re-render form with errors 
# assuming the modal is already open, you might want to just replace the form, rather than re-open the modal. 
$(".myFormSelector").html("<%= j render('books/modal_form', book: @book)%>") 
1

То, что вы делаете, не страшно, но вы могли бы несколько вещей немного почистить его. Я бы рекомендовал переместить бизнес-логику как из представления, так и из контроллера и вместо этого использовать шаблоны Presenter и Helper. Эти модели очень хорошо документированы в эти дни и имеют ряд преимуществ, в то числе:

  • продвижения тощих контроллеров
  • поощрения меньшие, более кратких фрагментов кода
  • способствующих Закон Деметры
  • сделать модульное тестирование проще

Вот довольно хорошее описание картины Presenter: https://gist.github.com/somebox/5a7ebf56e3236372eec4 или: http://eewang.github.io/blog/2013/09/26/presenting-the-rails-presenter-pattern/

В основном, как это работает, вы перемещаете свою бизнес-логику в отдельный класс под названием «ведущий». Этот класс содержит логику, которую вы обычно держите в своем контроллере.

Помощники также хорошо документированы и работают так же, как и для просмотров.Помощники много легче проверить, чем логику в представлениях. Для получения дополнительной информации: http://api.rubyonrails.org/classes/ActionController/Helpers.html

Это может выглядеть примерно так (обратите внимание, что это просто непроверенные, «псевдо» код, который я использую, чтобы проиллюстрировать рисунок):

# app/controllers/books_controller.rb 
    helper BooksHelper 

    def create 
     book = Book.find(params[:id]) 
     book.save 
     @presenter = BookPresenter(book) 
    end 

    # app/presenters/book_presenter.rb 
# move your 'fat' controller logic here 

    class BookPresenter 
     attr_reader :book, :page_type 

     def initialize(book, options={}) 
      @book = book 
     end 

     private 

     def page_type 
      # custom code here for determining page type 
     end 

     ... 
    end 

# app/helpers/books_helper.rb 
# move your view logic here 
module BooksHelper 
     def custom_modal(book_presenter) 
      if book_presenter.book.is_valid 
       handle_valid_book(book_presenter) 
      else 
       # handle invalid book 
      end 
     end 

     def handle_valid_book(book_presenter) 
      custom_list_modal if book_presenter.page_type == 'has_list' 
      custom_listless_modal if book_presenter.page_type == 'listless' 
      # other conditions 
     end 

     def custom_list_modal 
      # modularized JavaScript for pages with a list 
     end 

     def custom_listless_modal 
     # modularized JavaScript for pages without a list 
     end 

     ... 
    end 

Так что в этом деловая логика может быть легко протестирована в вашем приложении с использованием RSpec или любой другой структуры тестирования, которую вы используете. Сложность JavaScript снижается, а тестирование для него становится проще. Ваши JS-выходы могут быть определены отдельно в разных частичных файлах, если хотите, или просто вернуть фактический JS из вашего вспомогательного модуля. Сначала это сложная модель, но со временем все, скорее всего, станут более естественными, модульными и простыми в обслуживании.

Смежные вопросы