0

在 Rails 3.2 表单中,我有一个带有附加 setter 方法的 find_or_create 字段,并且我有一个当前正在运行 before_validate 的方法。我需要 before_validate 方法在 setter 方法之前运行。我应该如何修改我的代码来实现这一点?

我的表格包含:

<%= f.select(:country_id, Country.order(:name), :id, :name, include_blank:true) %>
<%= f.grouped_collection_select :state_id, Country.order(:name), :states, :name, :id, :name, include_blank: true %>
<%= f.text_field :new_state_name, placeholder: "..or enter a new state" %>
<%= f.input :city_name %>

在我的模型中

def city_name
 city.try(:name)
end

def city_name=(name)
  if name.present?
    set_city = City.find_or_initialize_by_name_and_state_id(name, self.state_id)
    if set_city.new_record?
      set_city.state_id = state_id
      set_city.save(:validate => false )
      self.city = set_city
    else
      self.city = set_city
    end
  end
end

before_validation :create_new_state

def create_new_state
  if new_state_name.present? && country_id.present?
    new_state = State.create( name: new_state_name, country_id: country_id )
    self.state = new_state.id
  end
end

这个想法是用户可以选择一个国家和一个州,然后输入一个城市名称,该名称是根据名称和州找到的。如果不存在这样的城市,则创建它。

此外,如果选择字段中不存在所需的状态,则用户可以改为在 new_state_name 字段中键入新状态。保存时,会创建新州,并应与新城市相关联(如果输入新州,则该城市必须是新的)。

我遇到的问题是 city_name 设置器似乎在该before_validation方法之前运行。因此,新城市是使用在状态选择中选择的任何值创建的(包括是否为空白?)。

有什么更好的方法来构建我的代码以达到预期的结果?谢谢

4

1 回答 1

0

我就是这样做的。(希望你不介意我稍微改变一下你的模型代码。)

delegate :name, to: :city, prefix: true
delegate :name, to: :state, prefix: true

attr_writer :city_name, :state_name
attr_accessible :city_name, :state_name

before_validate :find_or_create_city_and_state

validates :city, :state, presence: true

private

def find_or_create_city_and_state
  if state_name
    state = State.find_or_create_by_name_and_country_id(state_name, country.id)
    self.state = state

    if city_name # Nested since this doesn't make any sense without a state, presumably
      city = City.find_or_create_by_name_and_state_id(city_name, state.id)
      self.city = city
    end
  end
end

在您的表单中,调用字段city_namestate_name您应该一切顺利。

于 2012-06-30T15:37:24.067 回答