使用Rails 3.1,我有以下内容:
# state.rb
class State < ActiveRecord::Base
belongs_to :country, :touch => true
after_save :count_total_states
private
def count_total_states
total_states = State.where(:country_id => self.country_id).count
Country.where(:id => self.country_id).update_column(:state, total_states)
end
end
# states_controller.rb
class StatesController < ApplicationController
def create
@country = Country.find(params[:country_id])
@state = @country.states.build(params[:state])
@state.position = State.where(:country_id => @country.id).maximum(:position).to_i + 1
@state.save
end
end
当我为state
创建新对象时,出现以下错误:
NoMethodError in StatesController#create
undefined method `update_column' for #<ActiveRecord::Relation:0x1074b0e58>
返回控制器的方法是什么?请指教。
感谢。
答案 0 :(得分:3)
此错误是因为:
Country.where(:id => self.country_id)
返回ActiveRecord::Relation
个对象,而不是国家/地区。你可能应该做以下两件事之一:
Country.find(self.country_id).update_column(:state, total_states)
或
Country.where(:id => self.country_id).first.update_column(:state, total_states)
但是我建议使用第一个选项,因为它可以满足您的需求,通过ID查找记录。使用主键的位置有点时髦,你的目标是返回一个完全匹配,你知道它的ID,所以你应该直接抓住它。
注意:我还建议使用update_attribute
而不是update_column
,因为update_column
会跳过所有验证。除非你真的不能,否则验证是个好主意。
更好的是,您正在使用的行为实际上已封装到称为“计数器缓存”的标准Rails实践中。请参阅此blog post和此Railscast,以了解实现目标的更好方法。
答案 1 :(得分:0)
正如@Andrew所提到的,为了能够正确地更新我的记录(使用位置),我必须添加“first”这里是代码snipet以防万一
[ruby sinatra]
我的观点(所以你可以看到这些形式的值)
...
<form action="/device/<%= model.id %>/set-port-value" method="POST">
<input name="number" type="hidden" value="27"/>
<input name="value" type="hidden" value="11"/>
<input type="submit" value="POST" />
</form>
...
我的控制器
post '/device/:device_id/set-port-value' do
# Updating one record:
Port.where(number: params[:number]).first.update_column(:value, params[:value])
@models = Port.all
erb :'port/all'
end