Rails 4 ActiveRecord,如果记录存在,则使用id,否则创建新记录

时间:2014-11-10 19:00:03

标签: ruby-on-rails ruby activerecord ruby-on-rails-4

创建员工时,他会获得一个头衔。如果标题是唯一的,则记录会正常保存。如果标题不是唯一的,我想找到现有的标题,然后使用它。我无法弄清楚如何在创建动作中执行此操作。

employer.rb

class Employee < ActiveRecord::Base
  belongs_to :title, :class_name => :EmployeeTitle, :foreign_key => "employee_title_id"
  accepts_nested_attributes_for :title
end

employer_title.rb

class EmployerTitle < ActiveRecord::Base
  has_many :employees
  validates :name, presence: true, length: { maximum: 50 },
            uniqueness: { case_sensitive: true }
end

new.html.erb

<%= f.simple_fields_for :title do |title| %>
    <%= title.input :name, label: "Title" %>
<% end %>

employees_controller.rb

def create
  if EmployeeTitle.exists?(name: employee_params[:title_attributes][:name])
    # find title and use it?
  else
    @employee = current_user.employee.build(employee_params)
  end
  if @employee.save
    flash[:success] = "Employee #{@employee.title.name} created."
    redirect_to @employee
  else
    render 'new'
  end
end

编辑:使用first_or_create

def create
  EmployeeTitle.where(name: employee_params[:title_attributes][:name]).first_or_create do |title|
    @employee = current_user.employees.build(employee_params, :title => title)
  end
  if @employee.save
    flash[:success] = "Employee #{@employee.title.name} created."
    redirect_to @employee
  else
    render 'new'
  end
end

这使@employee超出了范围。错误:未定义的方法`save&#39;为零:NilClass。

此外,如果我这样做,无论其他员工数据是否有效,都不会创建标题?

使用私有方法

employee.rb

  private
    def title_attributes=(attributes)
      self.title = EmployeeTitle.find_or_create_by_name(name: attributes[:name])
    end

未设置该值。我得到一个&#34;不能空白&#34;验证错误。参数包括

employee: !ruby/hash:ActionController::Parameters
  title: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
    name: Consultant

以前没有!ruby / hash:ActiveSupport :: HashWithIndifferentAccess。

employee_params

  private
    def employee_params
      params.require(:employee).permit(
          title_attributes: [:id, :name],
      )
    end

1 个答案:

答案 0 :(得分:2)

您需要做的是改变这一点:

def create
  if EmployeeTitle.exists?(name: employee_params[:title_attributes][:name])
    # find title and use it?
  else
    @employee = current_user.employee.build(employee_params)
  end
  if @employee.save
    flash[:success] = "Employee #{@employee.title.name} created."
    redirect_to @employee
  else
    render 'new'
  end
end

用这个:

def create
  @employee = current_user.employee.build(employee_params)
  if @employee.save
    flash[:success] = "Employee #{@employee.title.name} created."
    redirect_to @employee
  else
    render 'new'
  end
end

现在,通过将此代码放在 app / models / employee.rb 文件中来覆盖title_attributes方法:

def title_attributes=(attributes)
  self.title = EmployeeTitle.find_or_create_by_name(attributes[:name])
end

现在,每次您创建名称已存在且具有特定名称的员工时,默认情况下都会将其用于将其关联为title。让控制器像以前一样 skinny

在此处详细了解find_or_create_by方法。

但是,你的问题的标题是:Rails 4,但你已经标记了ruby-on-rails-3.2。如果您使用的是Rails 4,那么您可以使用它:

EmployeeTitle.find_or_create_by(name: attributes[:name])