Newbie questions - storing and crossing controllers

Hi:

I've got a simple table that uses a form partial basically off of a
scaffold to handle the CRUD functions for a table, let's call this
table products.

I've got another table that has a related, but not constrained to,
table of information, it's a "tag" table. This table contains tags
that the user will input when they input the product information on the
the table above. The tag data is in a different table than the the
product data. The tag table is just id, product_id, name & timestamp.

I've got a partial in the view that is the products page to this tag
table. It shows up fine. But how do I capture the data and post it
back to the tag table? I've got a full controller with the standard
"create" method.

Any help you can provide would be appreciated!

Thanks,

Mike

Hey Mike,

The tables are related (see product_id).

So it is

Product < AR::B

has_many :informations

Information < AR::B

belongs_to :produduct

right?

Do something along the lines of

products_controller.rb

def create
@product = Product.new(params[:product]
if @product.save
@product.create_information(params[:information]
@product.save
end
end

Obviously
you need an params[:information] hash generated in the view Therefore
you might embed the following inside of your product/_form.rhtml

<% fields_for :information %>
<%= f.text_field :name %>
<% end %>

Cheers,
Jan

Hi Jan:

Thank you very much for your reply. This makes a lot of sense and I
totally understand why we're doing it this way.

I'm getting an error when I implement the fields_for in my parial view
/products/_for. Looks like just a syntax error with the "end'
statement (I'm on rails 1.1.6), but thought you might be able to shed
some light:

SyntaxError in Goals#new

Showing app/views/goals/_form.rhtml where line #32 raised:

compile error
./script/../config/../app/views/goals/_form.rhtml:32: parse error,
unexpected kEND, expecting $

What's weird is that line 32 is the line after the last line in my file
- tag heirarchy shouldn't matter, right? I tried it in 2 places in the
view and got the same result. Thank you very much again for your
response.

Mike

Hi Mike,

sorry but I’ve got to see some of your code to tell whats going wrong.

Here’s a form which is untested but should work. Please refer to the api documentation for the exact usage if something goes wrong or feel free to post the code with it’s corresponding errors.

<% form_for :product, @product do |f| %>
<%= f.text_field :name %>

<%= f.text_field :price %>

<% fields_for :information do |f| %>
<%= f.text_field
:name %>
<% end %>
<%= submit_tag ‘Create’ %>
<% end %>

Cheers,
Jan

Jan:

Thanks again! Actually, after some prodding, I did get it to work -
turned out it needed a "fieldset" link , which I found in agile rails
dev book. I'm so close, and I know the problem I'm having now is a
function of being a newbie. My problem is that I can get the product
id into the tags table, but for some reason the tag itself isn't being
automatically saved by rails. Here's what I've got (BTW: I used
"product" as the parent becuase that's what everyone uses. In reality,
it's "goals"), here's new & create methods from goals

goals_controller.rb:

def new
    @goal = Goal.new
    @goal_tag = GoalTag.new
    fk_timeperiod #to get fk for another field
    fk_goaltype #to get fk for another field
  end

  def create
    @goal = Goal.new(params[:goal])
    @goal_tag = GoalTag.new(params[:g])
    Goal.transaction do
       @goal_tag.goal_id = @goal
       @goal_tag.name = ??? ##THIS IS WHERE THE PROBLEM IS
       @goal.save!
       @goal_tag.save!
       flash[:notice] = 'Goal was successfully created.'
       redirect_to :action => 'show', :id => @goal
    end

    rescue ActiveRecord::RecordInvalid => e
       @goal_tag.valid? # force checking of errors even if products
failed
       render :action => :new

  end

here's the tags partial: (view/goal_tags/_form.rhtml)

  <fieldset>
  <legend>Tags...</legend>
  <p><% fields_for :goal_tags do |g|%>
  Enter Tags for this Goal (comma seperated)<br>
  <%= g.text_field :name %>
<% end %></p>
</fieldset>

this partial is just rendered inside the "new"rhtml for the goal(former
product):

/views/goals/new.rhtml

<h1>New goal</h1>

<%= start_form_tag :action => 'create' %>
  <%= render :partial => 'form' %>
  <%= render :partial => '/goal_tags/form' %> #HERE HERE
  <%= submit_tag "Create" %>
<%= end_form_tag %>

<%= link_to 'Back', :action => 'list' %>

Now just in case you need it, here's the goals _form partial:

<%= error_messages_for 'goal' %>

<!--[form:goal]-->
<p>
<label for="goal_goal_name">Goal name</label><br/>
<%= text_field 'goal', 'goal_name' %>
</p>
<div class="auto_complete"
     id="goal_goal_name_auto_complete" ></div>
<%= auto_complete_field :goal_goal_name,
:url=>{:action=>'autocomplete_goal_name'}, :tokens => ',' %>

<table>
<tr>
<td><label for="goalhist_goaltype_id">Goal Type</label></td>
<td><label for="goalhist_timeperiod_id">Timeperiod</label></td>
<td><label for="goal_public">Public</label></td>
</tr>
<tr>
<td><%= collection_select 'goal', 'goaltype_id', @all_gt, :id,
:goaltype %></p></td>
<td><%= collection_select 'goal', 'timeperiod_id', @all_tps, :id, :name
%></td>
<td><select id="goal_public" name="goal[public]"><option
value="false">False</option><option
value="true">True</option></select></td>
</tr>
</table>
<br>

<!--[eoform:goal]-->

So, as you can see from above, that is where the problem is, I can
committ the goal_id but not the name of the tag itself!!! The fact
that rails isn't handlign this automatically is what prompted me to
force it in the line in the create method with ??? in the controller
above. What am I missing?

Again, thank you so much for your help and your prompt reply!

Mike

Hey mike,

there are some things overcomplicated in your code.
I’m right now setting up a little toy project and will send it to you
by pm. You might then use this as a foundation…

Cheers,
Jan

Jan:

This stuff looks really great from what I can see. Problem is, I'm
having trouble upgrading to the RC2 of rails 1.2 becuase I can't get
svn in my path correctly, or at least that's the error i'm getting,
when I try and update to the version you mentioned of rails. See this
post (you've been so helpful, I had to ask!):

http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/c4b901ecbf10dd25/0036ee5145da6996#0036ee5145da6996

Thanks again!

Mike

Jan:

nevermind. I got it to work. This stuff looks pretty cool. I did a
bunch of other work already so I'm going to try and integrate it. But
at least i got to upgrade. Also I'm goign to need to look into routes
- there's some stuff in here that's different - a lot of XML or
something?

mike

Hi Mike,

no there shouldn’t be any xml. But the config/routes.rb is essential for this sexy new restful style of rails. Get a grip by searching for something like ‘restful’ ‘edge’ ‘rails’ on google.

Have fun.

Cheers,
Jan

Jan:

This was great. Got it working and I'm just amazed at all rails
offers, the more i work with it.

Here's a quick question for you. From the goals_controller.rb that you
sent, I don't quite understand this line:

tags.each {|tag| @goal.tags << Tag.find_or_create_by_name(tag)}

in the create method. I sort of understand it at the high level, but
can you explain a little better?

Thanks so much in advance!

Mike

Hi Mike,

when you use tags you want to be able to normalize them. I’ll explain by example:

You’ve got your models goals <-> tagging <-> tags
Now let’s assume:
user1 creates a new @goal1, writes up his description and tags it with: “Ronaldinho wonderful Champions League”

user2 creates another @goal2, writes up his description and tags it with: “Ronaldo asshat Champions League”

The tag-strings are split up to:
Ronaldinho
wonderful
Champions (2x)
League (2x)

Ronaldo
asshat

They now should get associated with their respective goals therefore we’ll iterate over the list of split up tags of each goal
@goal1.tags << Ronaldinho
@goal1.tags << wonderful
and so on

on goal2 it now happens that ‘Champions’ and ‘League’ are already in the tags-table so the don’t get created but found and associated with @goal2 (as well as the were already associated with @goal1 in their creation step). Because of this normalization

@tag = Tag.find_by_name(‘Champions’)
@tag.goals should give you an array of two goals (@goal1 and @goal2)

Cheers,
Jan