从多个地方渲染javascript:Rails方式

时间:2016-05-13 18:28:28

标签: ruby-on-rails coffeescript turbolinks

我有一个通过javascript渲染的模态表单。该模型名为 book

# 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回调会触发警报并使用更改更新列表。

现在我必须在另一个页面中添加此按钮,其中没有列表,所以我需要一个不同的回调(实际上并不重要哪些回调)。

所以,我必须添加到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个条件,因为&#34;创建书&#34;按钮在webapp上多次使用。

那么,有关设计模式的任何想法吗?

2 个答案:

答案 0 :(得分: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

它可能看起来像这样(请注意,这只是未经测试的,&#39;伪代码,我用它来说明模式):

    # 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。这是一个复杂的模式,最初采用,但随着时间的推移,一切都可能会感觉更自然,模块化,易于维护。

答案 1 :(得分:0)

您可能需要考虑在控制器中保留成功/错误逻辑,而是根据成功/失败使用单独的视图。那么你有一个create_success.js.coffee和一个create_error.js.coffee。每个人只处理自己的情况而不关心对方。注意:这是伪代码。

# 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)%>")