Search code examples
ruby-on-railsactiverecordattributesvirtual

Rails: Virtual attributes and form values


I have a Model Book with a virtual attribute for create a Editor from the Book form. The code looks like:

class Book < ActiveRecord::Base
  has_many :book_under_tags
  has_many :tags, :through => :book_under_tags
  has_one  :editorial
  has_many :written_by
  has_many :authors, :through => :written_by

  def editorial_string
   self.editorial.name unless editorial.nil?
   ""
  end
  def editorial_string=(input)
    self.editorial = Editorial.find_or_create_by_name(input)
  end
end

And the new form:

<% form_for(@book,
            :html => { :multipart => true }) do |f| %>
  <%= f.error_messages %>

...
  <p>
    <%= f.label :editorial_string , "Editorial: " %><br />
    <%= f.text_field :editorial_string, :size => 30  %> <span class="eg">Ej. Sudamericana</span>
  </p>
 ...

With this, when the form data no pass the validations I lost the data submited in the editorial field when the form is redisplayed, and also a new Editor is created. How I can fix this two problems? I am pretty new in ruby and I can't find a solution.

UPDATE my controller:

  def create
    @book = Book.new(params[:book])
    respond_to do |format|
      if @book.save
        flash[:notice] = 'Book was successfully created.'
        format.html { redirect_to(@book) }
        format.xml  { render :xml => @book, :status => :created, :location => @book }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @book.errors, :status => :unprocessable_entity }
      end
    end
  end

Solution

  • I believe its cause your Book#editorial_string method will always return "". Could simplify to the following:

      def editorial_string
       editorial ? editorial.name : ""
      end
    

    Update based on comment:

    Sounds like you want to do nested forms. (See accepts_nested_attributes_for in api docs) Note this is new in Rails 2.3.

    So if you update your Book class

    class Book < ActiveRecord::Base
      accepts_nested_attributes_for  :editorial
      ...
    end
    

    (You could also now remove the editorial_string=, editorial_string methods too)

    And update your forms to something like the following

    ...
    <% f.fields_for :editorial do |editorial_form| %>
      <%= editorial_form.label :name, 'Editorial:' %>
      <%= editorial_form.text_field :name %>
    <% end %>
    ...