我有一个通过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上多次使用。
那么,有关设计模式的任何想法吗?
答案 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)%>")