ruby-on-rails – 处理与虚拟属性对应的多参数属性的正确方法
我有一个Rails应用程序,其中包含一个包含birthdate属性的模型.这对应于使用ActiveRecord日期类型定义的数据库中的列.有了这个,我可以使用date_select表单助手方法在我的视图中将其渲染为三选输入.然后将对应于该字段的表单参数序列化回控制器作为生日(1i),生日(2i)和生日(3i).因此,我可以在我的模型上的控制器中使用标准的update_attributes方法来更新模型上的所有字段.
我现在正在尝试使用 我目前正在解决这个问题如下: 我在app / models / person.rb中的模型: class Person < ActiveRecord::Base attr_encrypted :birthdate end 我在app / controllers / people_controller.rb中的控制器: class PeopleController < ApplicationController def update # This is the bit I would like to avoid having to do. params[:person] = munge_params(params[:person]) respond_to do |format| if @person.update_attributes(params[:person]) format.html { redirect_to @person,notice: 'Person was successfully updated.' } format.json { head :no_content } else format.html { render action: "edit" } format.json { render json: @person.errors,status: :unprocessable_entity } end end end private def munge_params(params) # This separates the "birthdate" parameters from the other parameters in the request. birthdate_params,munged_params = extract_multiparameter_attribute(params,:birthdate) # Now we place a scalar "birthdate" where the multiparameter attribute used to be. munged_params['birthdate'] = Date.new( birthdate_params[1],birthdate_params[2],birthdate_params[3] ) munged_params end def extract_multiparameter_attribute(params,name) # This is sample code for demonstration purposes only and currently # only handles the integer "i" type. regex = /^#{Regexp.quote(name.to_s)}((d+)i))$/ attribute_params,other_params = params.segment { |k,v| k =~ regex } attribute_params2 = Hash[attribute_params.collect do |key,value| key =~ regex or raise RuntimeError.new("Invalid key "#{key}"") index = Integer($1) [index,Integer(value)] end] [attribute_params2,other_params] end def segment(hash,&discriminator) hash.to_a.partition(&discriminator).map do |a| a.each_with_object(Hash.new) { |e,h| h[e.first] = e.last } end end end 我的观点app / views / people / _form.html.erb: <%= form_for @person do |f| %> <%= f.label :birthdate %> <%= f.date_select :birthdate %> <% f.submit %> <% end %> 处理这种类型的属性的正确方法是什么,而不必像这样引入params数组的临时替换? 更新: 另一个更新: 这是我目前的解决方案,基于Chris Heald的回答.此代码应添加到Person模型类中: class EncryptedAttributeClassWrapper attr_reader :klass def initialize(klass); @klass = klass; end end # TODO: Modify attr_encrypted to take a :class option in order # to populate this hash. ENCRYPTED_ATTRIBUTE_CLASS_WRAPPERS = { :birthdate => EncryptedAttributeClassWrapper.new(Date) } def column_for_attribute(attribute) attribute_sym = attribute.to_sym if encrypted = self.class.encrypted_attributes[attribute_sym] column_info = ENCRYPTED_ATTRIBUTE_CLASS_WRAPPERS[attribute_sym] column_info ||= super encrypted[:attribute] column_info else super end end 此解决方案按原样工作,但如果attr_encrypted采用将动态构造ENCRYPTED_ATTRIBUTE_CLASS_WRAPPERS哈希的:class选项,则会更好.我将看看我可以扩展/ monkeypatch attr_encrypted的方法来做到这一点.要点:https://gist.github.com/rcook/5992293. 解决方法
您可以对模型进行monkeypatch以通过column_for_attribute调用.我没有对此进行过测试,但它应该导致生日字段上的反射而不是返回encrypted_birthday字段的反射,这应该导致multiparam属性正确分配(因为AR将能够推断字段类型):
def column_for_attribute(attribute) if encrypted = encrypted_attributes[attribute.to_sym] super encrypted[:attribute] else super end end 我们每this line修补一次column_for_attribute,以便AR可以推断出该列的正确类型.它需要弄清楚“birthday”的参数应该是DateTime类型的whatnot,并且不能从虚拟属性推断出.将反射映射到实际列应解决该问题. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |