Rails:按特定顺序创建属性

时间:2012-03-14 19:28:35

标签: ruby-on-rails activerecord associations

在我的Rails应用程序中,我有用户。用户被要求提供他们的家乡城市和地区/社区。

class User < ActiveRecord::Base
  belongs_to :city
  belongs_to :district
end

class City < ActiveRecord::Base
  has_many :users
  has_many :districts
end

class District < ActiveRecord::Base
  has_many :users
  belongs_to :city
end

在表单中,我使用User模型上接受字符串的虚拟属性构建关联(如果相关,请在下面提供更多信息)。

在控制台中,这一切都很有效,但在UI中它不起作用。问题似乎是,我可以通过表单获得city_name没有问题,但是当我尝试以相同的形式分配城市和地区时,它总是失败。换句话说,质量分配不起作用。

@user.update_attributes(params[:user])

相反,我唯一能够弄清楚的是从表单提交中手动设置每个键,例如:

@user.name = params[:user][:name] if params[:user][:name]
@user.city_name = params[:user][:city_name] if params[:user][:city_name]
@user.district_name = params[:user][:district_name] if params[:user][:district_name]

这种方法有效,但它很痛苦,很脆弱,并且感觉一切都错了,因为它开始用很多逻辑来控制控制器。

我的问题是:

  1. 有没有办法按特定顺序创建或更新属性,理想情况是在模型中,以便控制器不必担心所有这些?

  2. 我这样做错了吗?如果是这样,哪种方法会更好。


  3. 额外信息

    以下是我如何使用用户模型上的虚拟属性构建关联,以防与任何潜在的回答者相关:

    我希望用户只需输入一个名称就可以选择一个城市,例如“Chicago,IL”。这样可以正常使用用户模型上的虚拟属性,如下所示:

    def city_name
      city.try :full_name
    end
    
    def city_name=(string)
      self.city = City.find_or_create_by_location_string( string )
    end
    

    用户只有从他们选择的城市中查找或创建区域才有意义。这种方式略有不同:

    def district_name
      district.try :name
    end
    
    def district_name=(string)
      if self.city.nil?
        raise "Cannot assign a district without first assigning a city."
      else
        self.district = self.city.districts.find_or_create_by_name( string )
      end
    end
    

    在模型层中,这些工作正常,只要设置了city_name和district_name,区域关联就会按预期工作。

1 个答案:

答案 0 :(得分:1)

我认为你可以做一些事情来清理它。首先,您可以使用委托来清理代码。例如

delegate :name, :to => :city, :prefix => true, :allow_nil => true

你可以这样做

user = User.create
user.city_name # nil
city = City.create(:name => 'chicago')
user.city = city
user.save
user.city_name # chicago

它会起作用。

接下来,我会说从你的模型中取出name-to-id逻辑。您可以在表单中(例如,ajax搜索将区域ID /城市ID放入隐藏字段)或控制器中执行此操作。然后只需正常分配城市/地区。