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