如何使用rails中的create方法创建多个记录并处理验证?

Ahm*_*mza 1 ruby ruby-on-rails ruby-on-rails-4

我将参数中的一组属性发送到我的控制器,如果创建记录有任何错误,我需要处理验证错误.

因为我需要一次创建多个组.

参数

  Parameters: {"group"=>[{"sort_by"=>"id", "template_ids"=>[182], "name"=>"Csdfwses", "count"=>1}, {"sort_by"=>"id", "template_ids"=>[181], "name"=>"rthydrt", "count"=>1}]}
Run Code Online (Sandbox Code Playgroud)

所以我的控制器的create方法是这样的:

def create
  @groups = Group.create group_params
   if @groups
    render json: { success: true, message: "#{@groups.length} groups created" }
   else
    render_422 @groups, 'Could not save groups.'
   end
end
Run Code Online (Sandbox Code Playgroud)

如果在创建任何记录时发生任何错误,我想处理这种情况,以便在创建它之后应该显示错误消息.

使用上述方法,error此处无法使用方法.如何显示错误消息?

我尝试过使用begin-rescue:

 def create
  begin
   @groups = Group.create! group_params
    if @groups
     render json: { success: true, message: "#{@groups.length} groups created" }
    else
     render_422 @groups, 'Could not save groups.'
    end
  rescue ActiveRecord::RecordInvalid => invalid
    render json: { success: false, message: "#{invalid.record.errors.messages}" }, status: 500
  end
 end
Run Code Online (Sandbox Code Playgroud)

但我正在寻找更清洁的方法,如果有的话?

Dbz*_*Dbz 6

您希望将散列数组传递给以model.create一次创建多个记录。

def create
  @groups = Group.create group_params
   if @groups.all? { |group| group.persisted? }
    render json: { success: true, message: "#{@groups.length} groups created" }
   else
    render_422 @groups, 'Could not save groups.'
   end
end
Run Code Online (Sandbox Code Playgroud)

如果您想显示任何验证错误,那么您将需要查看model.errors或查看可以查看的一系列错误model.errors.full_messages

def create
  @groups = Group.create group_params
   if @groups.all? { |group| group.persisted? }
    render json: { success: true, message: "#{@groups.length} groups created" }
   else
    errors = @groups.select(&:invalid?).map{ |g| g.errors.full_messages }.join("<br/>") 
    render_422 @groups, "Could not save groups. Here are the errors: #{errors}"
   end
end
Run Code Online (Sandbox Code Playgroud)

您将希望更好地格式化错误,但这是一个简单的示例。


max*_*max 5

您通常会使用accepts_nested_attributes- 但这需要某种层次关系:

class Company < ActiveRecord::Base
  has_many :employees
  accepts_nested_records_for :employees
  validates_associated :employees
end

class Employee < ActiveRecord::Base
  belongs_to :company
  validates_presence_of :name
end

c = Company.new(name: 'Acme', employee_attributes: [
  { name: 'Wile E. Coyotee' },
  { name: 'Bugs Bunny' },
  { name: nil } # invalid
])

c.valid? # false
c.save # false
Run Code Online (Sandbox Code Playgroud)

那么如果没有父模型,你会怎么做呢?创建一个充当父关联的模型:

# A fake parent model for groups.
# This is not a ActiveRecord model
# It's is not backed by a database table.
class GroupCollection
  include ActiveModel::Model
  attr_accessor :groups

  def initialize(groups_attributes: [], **kw_args)
    super
  end

  # mimics behavior of accepts_nested_attributes
  # takes either an array or a key/val hash:
  # { 1 => {'name' => 'foo'} }
  def groups_attributes=(attrs)
     # normalize key/val hash
     attrs = attrs.values if attrs.is_a?(Hash)
     self.groups = attrs.map {|h| Group.new(h) }
  end

  # mimics behavior of validates_associated
  def valid?
    errors.clear
    # alternatively you can aggregate errors for
    # the nested records on the parent object
    if groups.reject { |g| g.valid? }.any?
      errors.add(:groups, 'are invalid.')
    end
    errors.none?
  end

  def save
    return false unless valid?
    save_in_transaction
  end

  def save!
    raise ActiveRecord::RecordInvalid and return unless valid?
    save_in_transaction
  end

  private 
    def save_in_transaction
      # use a transaction so changes are rolled back if a save fails.
      Group.transaction do
        groups.reject { |g| g.save! }.none? 
      end
    end
end
Run Code Online (Sandbox Code Playgroud)
class GroupsController

  def create
    @collection = GroupCollection.new(groups_params)
    @groups = @collection.groups

    if @collection.save
      c = @groups.length
      render json: { 
            success: true, # anti-pattern! - rely on the response code instead
            message: "#{c} #{pluralize(c, 'group')} created" 
      }, status: :created
    else
      # you can get the error messages by iterating through @groups
      # and calling `.errors.full_messages` on each
      render_422 @groups, 'Could not save groups.'
    end
  end

  def collection_params
    params.permit(groups_attributes: [:name, :foo, :bar])
  end
end
Run Code Online (Sandbox Code Playgroud)