Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding model attribute readers does not affect simple_form input fields

I am using simple_form and want to override readers for model attributes.

Thus following does not work

class C < ActiveRecord::Base

  # it has attribute named pack

  def pack
    "Some value"
  end

end

In view there is following code

<%= simple_form_for @c do |f| %>
  <%= f.input :pack %>
<% end %>

thus it should show form with input box having value "Some value" but it is blank. Why doesn't override work with simple_form?

like image 864
amitamb Avatar asked May 26 '12 16:05

amitamb


2 Answers

I figured this out, my comment was basically correct, simple_form leans on Rails form helpers which use read_attribute to get the value from an ActiveRecord object thus reading the value in the database and not using your method. A symptom of coupling persistence/domain/presentation. The way around this is:

 <%= f.input :pack, :input_html => { :value => @c.pack } %>
 # or
 <%= f.input :pack, :input_html => { :value => f.object.pack } %>

Or if you want this to be default behaviour you can create your own form builder on top of simple_for such as:

# lib/my_form_builder.rb **

class MyFormBuilder < SimpleForm::FormBuilder                                                                                               
  def input(attribute_name, options={}, &block)                                 
    options[:input_html] ||= {}                                                 
    options[:input_html][:value] = object.send(attribute_name)                  
    super(attribute_name, options, &block)                                                          
  end
end

And in your form:

<%= simple_form_for @c, :builder => MyFormBuilder do |f| %>
  <%= f.input :pack %>
<% end %>

** in Rails 3 I don't think lib is added to the load path by default so you might need to add it and restart you app or put it in app/models (disclaimer not a good idea, lib is better).

like image 133
Kris Avatar answered Nov 11 '22 10:11

Kris


In Rails 3.2 at least, it isn't using read_attribute directly anymore. But if you're using a text field, it uses InstanceTag.value_before_type_cast to retrive the value. This uses:

object.respond_to?(method_name + "_before_type_cast") ?
  object.send(method_name + "_before_type_cast") :
  object.send(method_name)

(where method_name is the attribute name in that context)

So if you'd like to make sure that the form uses your attribute accessor, add the following alias:

  alias pack_before_type_cast pack

That works for me, just make sure to return a string there...

like image 34
Michael Reinsch Avatar answered Nov 11 '22 10:11

Michael Reinsch