Topic: creating an edit form that saves info to multiple tables...

I am working on making a todo list application as a way to learn rails. I already have set up two tables (todos and details) that are linked by a foreign key todo_id in the details table.

Currently the user can create a new todo item on the main page that creates the title(description in the db) for the item.
There is an edit button associated with each todo item. The detail for each item is stored in the details table (I only retrieve it if/when it is asked for and display it in a div using ajax - I already coded this).

I am using belongs_to :todo in the detail model and had_one :detail in the todo model.
I am at a loss as to how to use these to show any detail that already exists for the todo item in the edit form or how to update that detail when the edit form is submitted.

Basically it comes down to not completely comprehending has_one, belongs_to. So if you can help here or point me to a good resource that would be greatly appreciated!

Bob

Re: creating an edit form that saves info to multiple tables...

You should check out http://developer.apple.com/tools/rubyonrails.html

Even if you aren't using a mac it's a great step by step guide on rails.  The site should have what you're looking for.

Re: creating an edit form that saves info to multiple tables...

nvision, thanks for the reference I will definitely take some time to read through it!

here's where I am at with things at the moment...

*** todo_controller

def edit
  @todo = Todo.find(params[:id])
end


*** _form (partial called from edit.rhtml)

<%= error_messages_for 'todo' %>

<% form_for :todo, :url => { :action => :update, :id => @todo } do |form| %>
    <p><label for="todo_description">Description</label><br/>
    <%= form.text_field :description %></p>

    <p><label for="todo_done">Done</label><br/>
    <%= form.text_field :done %></p>

    <p><label for="todo_position">Position</label><br/>
    <%= form.text_field :position %></p>

    <p><label for="todo_detail">Details</label><br/>
    <%= form.text_area :detail, :rows => 3, :columns => 40 %></p>
   
    <%= submit_tag "Submit Changes", :class => "submit" %>

<% end %>


when I choose edit for items that have a detail associted with them already I get the object identifier of the detail object (#<Detail:0x39ce8f4>). How do I access what is in the detail of the detail object?

Re: creating an edit form that saves info to multiple tables...

Perhaps you should merge the two models. It sounds like the detail is just a block of text, so it could easily be a text column in the todos table. Or am I misunderstanding something?

Railscasts - Free Ruby on Rails Screencasts

Re: creating an edit form that saves info to multiple tables...

Detail at this point is just a block of text but there are two reasons why I am hoping to do it this way.

One is simple to help learn how to do this for other more complicated things down the road...

The other is because I don't see a reason to load the details for every item in a todo list unless they are needed. Since I don't display them until requested this seems to make sense as well as reduce overhead should there be mutiple users with a large lists later down the road.

Re: creating an edit form that saves info to multiple tables...

See my tutorial on creating a form with two models. However, because this is a has_one association it will be a little different in the create action. Specifically you will use build_detail instead of details.build:

def create
  @todo = Todo.new(params[:project])
  @detail = @todo.build_detail(params[:detail])
  if @todo.save
    redirect_to :action => 'index'
  else
    render :action => 'new'
  end
end

Does that answer your question?

Railscasts - Free Ruby on Rails Screencasts

Re: creating an edit form that saves info to multiple tables...

The way I've ended up creating the update method is this:

def update
    @todo = Todo.find(params[:id])
    #find detail based on todo_id (foreign key)
    @detail = Detail.find_item_description(params[:id])
   
    if @todo.update_attributes(params[:todo]) && @detail.update_attributes(params[:detail])
      flash[:notice] = 'Todo was successfully updated.'
      redirect_to :action => 'show', :id => @todo
    else
      render :action => 'edit'
    end
end

Is there a more efficient way to do this? What is build_detail, I can't find any info on it...
Thanks!

Re: creating an edit form that saves info to multiple tables...

You can call @todo.detail to grab the detail for updating.

def update
    @todo = Todo.find(params[:id])
    @detail = @todo.detail
   
    if @todo.update_attributes(params[:todo]) && @detail.update_attributes(params[:detail])
      flash[:notice] = 'Todo was successfully updated.'
      redirect_to :action => 'show', :id => @todo
    else
      render :action => 'edit'
    end
end

The build_detail method is a magic method ActiveRecord adds when you set up the has_one association. See the link for details.

Railscasts - Free Ruby on Rails Screencasts