RoR:在创建控制器方法之前验证非模型字段

时间:2014-06-22 04:03:16

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

我需要在create方法之前验证字段

在我的_form.html.erb中我有两个模型,一个是所有者模型,另一个是我创建的模型以获得其他参数,我需要在进入create方法之前验证这些参数,我可以使用如果,但这不是最好的做法。

def create
  @customer = Customer.new(customer_params)
  #read the city name, since this is requested by city name (string) and it shoud be "id" in the system
  city = city_params()
  @customer.city_id = City.find_by(name: city["name"]).id
  respond_to do |format|
    if @customer.save
      format.html { redirect_to @customer, notice: 'Customer was successfully created.' }
      format.json { render action: 'show', status: :created, location: @customer }
    else
      format.html { render action: 'new' }
      format.json { render json: @customer.errors, status: :unprocessable_entity }
    end
  end
end

我需要验证城市名称,因为客户所有者必须拥有city_id,并且_form请求名称(字符串),所以我需要找到城市,但之前我需要验证城市名称是否有值它存在,

如何在模型中验证?

3 个答案:

答案 0 :(得分:1)

如果我是你,我会首先将所有这些逻辑保留在控制器中并使用过滤器来查找城市:

class CustomersController < ApplicationController
  before_action :find_city, only: [:create, :update]

  def create
    @customer = Customer.new(customer_params)
    #read the city name, since this is requested by city name (string) and it shoud be "id" in the system
    @customer.city_id = @city.try(:id) # This returns `nil` if the city was not found
    respond_to do |format|
      if @customer.save
        format.html { redirect_to @customer, notice: 'Customer was successfully created.' }
        format.json { render action: 'show', status: :created, location: @customer }
      else
        format.html { render action: 'new' }
        format.json { render json: @customer.errors, status: :unprocessable_entity }
      end
    end
  end

private

  def find_city
    @city = City.find_by(name: params[:city][:name]) # No need for strong parameters for this
  end
end

然后确保您在city_id课程中验证Customer的存在:

class Customer < ActiveRecord::Base
  validates :city_id, presence: true
end

稍后,如果您发现需要从控制器中提取此逻辑,请考虑创建service objectform object。因为这是一个简单的案例(只涉及2个类),我现在暂时不会创建这些构造。控制器层足以处理这个简单的逻辑。

为什么不直接将逻辑移到模型中?我可以从经验中告诉你,你不想用大量涉及其他模型类的逻辑搞乱你的模型。在我看来,CustomerCity不太了解。

答案 1 :(得分:0)

<强> before_validate

可能在你的模型中使用before_validate回调:

#app/models/customer.rb
Class Customer < ActiveRecord::Base
   attr_accessor :city_name
   before_validate :set_city

   private

   def set_city
       city_id = City.find_by(name: city_name).id
   end
end

-

自定义验证方法

我认为最重要的是你最好使用自定义验证方法。您基本上希望将用户返回到表单,并显示错误消息&#34; City not found&#34;或类似的;这完全在custom validation method的范围内:

#app/models/customer.rb
Class Customer < ActiveRecord::Base
   validate :check_city_id

   private

   def check_city_id
       errors.add(:city_id, "City doesn't exist") unless City.try city_id
   end
end

-

<强>系统

这种问题可以通过简单地给用户选择输入中的id来处理;而不是通过name选择:

#app/views/customers/new.html.erb
<%= form_for @customer do |f| %>
   <%= f.select :city_id, City.all.collect {|p| [ p.name, p.id ] } %>
<% end %>

我认为您的方法是让用户能够选择城市name,然后在后端进行验证是非常低效的;同时为用户提供一套严格的选项,以便按城市选择买家更为健全

答案 2 :(得分:-1)

我们有一些名为callbacks http://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html的东西..使用这个我们可以在模型中触发我们所需的验证。

您可以创建自己的验证逻辑,例如

before_create :method_name 

def method_name
 your logic.....example: validates :city_name ..

end