views:

2337

answers:

3

Hi. 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
+1  A: 

The first problem is that

def editorial_string
  self.editorial.name unless editorial.nil?
  ""
end

will always return "" because that is the last line.

def editorial_string
  return self.editorial.name if editorial
  ""
end

would fix that problem. As far as why the validations don't pass, I don't know, what are you doing in the controller? What validation errors are you getting?

Ben Hughes
Thanks for the fix. But I have the same problem: I lost the value inserted in the form in the editorial form. In the controller I have: 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) } else format.html { render :action => "new" } end end end
Castro
can you look in your development server logs and paste your params. From there I would try to create a new book at script/console with those params and see if you can find anything that looks out of place (or that fixes it).
Ben Hughes
Here: Parameters: {"commit"=>"Crear", "authenticity_token"=>"1e0b41988b8c3908a52ce5422e0852a76afbf1a4", "action"=>"create", "author_string"=>"", "controller"=>"books", "book"=>{"uploaded_picture"=>"", "title"=>"", "isbn"=>"00", "published"=>"", "pages"=>"100", "description"=>"", "editorial_string"=>"AAAAAAAA"}}
Castro
ok, so open up script/console, assign those params to a variable, and try to create a Book on the console. What you have *should* work.
Ben Hughes
Yes. That works. But my problem is that if I get a validation error in the data submited (for example the ISBN no validates), when the form is redisplayed showing the errors I lost the value of the editorial field (the submited value for this field). I think that @rnicholson's answer is right, I need accepts_nested_attributes_for, but I don't have that version of rails yet :(.
Castro
if editorial_string correctly assigns editorial, then it should persist even on a validation failure. rnicholson's answer is sort of right (one can argue about law of demeter). Try at the console simulating a validation failure and see if book.editorial still contains data.
Ben Hughes
+1  A: 

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 %>
...
rnicholson
Thanks. But again, I have the problem that I lost the value of the field editorial when a form redisplayed occurs because a validation error. And also I don't know how to prevent the creation of a editorial when the book don't validate.
Castro
Thanks for your reply, I am using rails 2.1.0-6 installed by ubuntu aptitude tool, so I don't have that feature. I think that I will change the form and disallows the creation of Editors in the Book form.
Castro
A: 

Take a look at this podcast http://railscasts.com/episodes/167-more-on-virtual-attributes. I think you should move your find_or_create from the editorial_string=(input) method to call back after the save.

dave elkins