accepted_nested_attributes_for with validations并使用find_or_create_by

时间:2016-06-03 20:14:15

标签: ruby-on-rails ruby

我有user模型和town模型。一个user belongs_to town

# models/user.rb
class User < ApplicationRecord
  belongs_to :town
  accepts_nested_attributes_for :town
  validates :last_name, presence: true
end


# models/town.rb
class Town < ApplicationRecord
  has_many :users
  validates :name, presence: true
  validates :name, uniqueness: true
end

你去创建一个新的user记录:有一个text_box,以便放入相关城镇的name。提交后,rails应用程序应执行以下操作:

  • 使用find_or_create_by。去检查是否已存在传递了town属性的name记录。
    • 如果town记录与给定的name属性存在,则只需将现有town记录与此新user记录相关联
    • 如果town记录与给定的name属性不存在,则使用该town属性创建新的name记录,并将该记录与此user相关联{1}}记录
  • 如果任何验证失败,请不要创建user记录或town记录并重新呈现表单。

我遇到了这个问题。 This question建议将autosave放在belongs_to :town语句上,并定义一个名为autosave_associated_records_for_town的方法。但是:我无法让它发挥作用。

欣赏它!

1 个答案:

答案 0 :(得分:4)

请尝试解决方案。它对我有用。

用户

# user.rb

class User < ActiveRecord::Base
  belongs_to :town

  accepts_nested_attributes_for :town
  validates :last_name, presence: true
end

<强>镇

# town.rb

class Town < ActiveRecord::Base
  has_many :users
  validates :name, presence: true
end

<强>控制器

# users_controller.rb

respond_to :html    

def create

  # ...
  @user = User.new(user_params)
  @user.town = Town.find_or_initialize_by(user_params[:town_attributes])
  if @user.save
    respond_with(@user)
  else
    render 'new'
  end
end

# ...

def user_params
  params.require(:user).permit(:last_name, :email, :town_id, town_attributes: [:name])
end

查看

# users/_form.html.erb

<%= form_for(@user) do |f| %>

  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :email %><br>
    <%= f.text_field :email %>
  </div>


  <div class="field">
    <%= f.label :last_name %><br>
    <%= f.text_field :last_name %>
  </div>

  <%= f.fields_for :town, @town do |bldr| %>
    <div class="field">
      <%= bldr.label :name, 'Town name' %><br>
      <%= bldr.text_field :name %>
    </div>
  <% end %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Validations

<强>更新

请考虑将validates_associated添加到用户的验证中。 这是相关的documentaion

class User < ActiveRecord::Base
  belongs_to :town

  accepts_nested_attributes_for :town
  validates :last_name, presence: true
  validates :town, presence: true
  validates_associated :town
end

enter image description here

通常来说,在这种情况下你可以删除validates :town, presence: true。没有它,验证将有效。