如何使用事务以多模型forms显示错误消息?
组织和用户这两个模型具有1:多的关系。 我有一个组合注册表单,组织和该组织的用户都可以注册。
我遇到的问题是:当为用户提交无效信息时,它会再次呈现表单,但不显示用户的错误消息(例如“用户名不能为空”)。 表单在提交有效信息时确实有效,并且显示组织的错误消息,而不是用户。
我应该如何调整下面的代码,以便显示用户的错误消息?
def new @organization = Organization.new @user = @organization.users.build end def create @organization = Organization.new(new_params.except(:users_attributes)) #Validations require the organization to be saved before user, since user requires an organization_id. That's why users_attributs are above excluded and why below it's managed in a transaction that rollbacks if either organization or user is invalid. This works as desired. @organization.transaction do if @organization.valid? @organization.save begin # I executed next line in debugger (with invalid user info), which correctly responds with: ActiveRecord::RecordInvalid Exception: Validation failed: Email can't be blank, Email is invalid, Username can't be blank, etc. @organization.users.create!(users_attributes) rescue # Should I perhaps add some line here that adds the users errors to the memory? raise ActiveRecord::Rollback end end end if @organization.persisted? flash[:success] = "Yeah!" redirect_to root_url else @user = @organization.users.build(users_attributes) # Otherwise the filled in information for user is gone (fields for user are then empty) render :new end end
表单视图包括:
# Other fields # Other fields
错误消息部分如下:
更新:按照Rob的回答,我到达了下面的错误部分。 这仍然不会显示用户的错误消息。 我在下面的代码中添加了调试器响应,出于某种原因nested_model.errors.any?
返回false,而控制器内的调试器(见上文)确实为用户返回错误消息。
The form contains .
# Debugger: responds with "local-variable" for "defined?(nested_models)" and for "nested_models.any?" returns true. # Debugger: "nested_model" has the same values as "nested_models.any?", as you would expect. But for "nested_model.errors.any?" it returns false, which it shouldn't. #Initially had "unless nested_model.valid?" but then errors for User are immediately displayed on loading the form page (new method).
尝试添加validates_associated :users
您在组织中的has_many :users
关联下的has_many :users
。
http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates_associated
您是否在救援区成功编写了代码?
rescue ActiveRecord::RecordInvalid => exception # do something with exception here raise ActiveRecord::Rollback @organization.users.build if @organization.users.blank? render :new and return
此代码看起来会创建一个新的空用户,无论validation不正确。 假设组织没有用户,则渲染new将简单地返回没有错误,因为用户已成功创建。
这种方法的控制流程有一些结果,肯定需要进一步细分。 我会使用byebug并使用不正确的组织遍历块,然后使用错误的名称。 然后是一个空组织,其用户属性不正确。
组织has_many:用户和用户belongs_to:组织
organization.rb
accepts_nested_attributes_for :users
new.html.erb
<%= form_for @organization, url: next_url do |f| %> <%= render 'shared/error_messages', object: @organization %> <%= f.text_field :name %> # Other fields <%= f.fields_for(:users,@organization.users.build) do |p| %> <%= p.email_field :email %> # Other fields <% end %> <%= f.submit "Submit" %> <% end %>
在控制器中
def create @organization = Organization.new(new_params) if @organization.save flash[:success] = "Yeah!" redirect_to root_url else render :new end end
这与这个问题非常相关。 关键是<%= render 'shared/error_messages', object: f.object %>
,我认为,它只是在传递的对象上调用.errors
方法(在本例中为organization
)。
但是,由于user
错误与user
对象一起存在,因此不会返回它们,因此不会显示它们。 这需要简单地更改视图逻辑以在各种user
模型上显示.errors
的结果。 你想怎么做取决于你。 在链接的线程中,接受的答案有错误消息显示代码内联而不是部分,所以你可以这样做,但它会有点多余。
我会修改我的shared/error_messages.html.erb
文件以检查另一个被称为nested_models
传递本地。 然后它将使用它来搜索关联的模型并在其上包含错误。 我们只需要检查它是否首先被定义,以便您的其他视图没有嵌套模型不会导致它引发错误。
共享/ error_messages.html.erb
<% if object.errors.any? %>
<% end %>
然后你只需要在视图中更改一行:
<%= render partial: 'shared/error_messages', locals: { object: @organization, nested_models: @organization.users } %>
看起来你的控制器中有很多不可测试的逻辑。 看起来对你来说逻辑会更好地使用简单的FormObject模式。 https://robots.thoughtbot.com/activemodel-form-objects