Create and save nested data

Hi,

I am working on a patent database, where the user can first search the
patent database and then save the found patent with connected patents
(called familymembers). So I have a page called “patent” where the
search is done and all values that I need for the database are
available.

From that page I want to store the patent with his familymembers into
my database, to watch them. So I have the following models

class Watchedfamily < ActiveRecord::Base
has_many :watchedmembers
accepts_nested_attributes_for :watchedmembers
end

class Watchedmember < ActiveRecord::Base
belongs_to :watchedfamily
end

On my patent page I tried to save the data with a form that looks like
this (I had to define the controller that i want to use, because this
form is not in the watchedfamiles view!):

<% form_for :watchedfamily, :url => {:controller =>
“watchedfamilies”, :action => “create” } do |f| %>
<%= f.text_field :Prio_No, :value => @prio_no %>
<%= f.text_field :title, :value => @title %>
<%= f.fields_for :watchedmembers_attributes do |x| %>


<%= x.text_field :Pub_No, :value => “Test” %>


<%end%>

<%= submit_tag “Save hidden form” %>


<% end %>

That is not working! Error is: “can’t convert Symbol into Integer”

If I create the nested data directly in the watchedfamilies by
clicking new and using the form below it is working:

<%= form_for(@watchedfamily) do |f| %>

<%= f.label :Prio_No %>
<%= f.text_field :Prio_No %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.fields_for :watchedmembers do |x| %>

<%= x.text_field :Pub_No, :value => "Test" %>

<%end%>
<%= f.submit %>
<% end %>

The problem is that my first approach is generating the following
request:

Parameters: {“watchedfamily”=>{“Prio_No”=>“123456”,
“title”=>“Whatever”, “watchedmembers_attributes”=>{“Pub_No”=>“Test”}},
“commit”=>“Create Watchedfamily”}

Where my second approach, directly from the watchedfamilies is
generating the following request:

Parameters: {“watchedfamily”=>{“Prio_No”=>“123456”,
“title”=>“Whatever”,
“watchedmembers_attributes”=>{“0”=>{“Pub_No”=>“Test”}}},
“commit”=>“Create Watchedfamily”}

First one watchedmembers_attributes is a string, second one is an
array.

If I change the line in my form from
<%= f.fields_for :watchedmembers_attributes do |x| %>
to
<%= f.fields_for :watchedmembers do |x| %>

I got the error: “Watchedmember(#26928120) expected, got
Array(#5756196)”

Maybe I am on a wrong track. I just want to save a nested value
(patentfamily with its family members to my database!)
I already watched tutorials and asked google, but I didn’t find a
solution to my problem. I hope I get help here!!!

Cheers,
Sebastian

OK, I don’t know why but it happens all the time that after posting a
problem in a forum I am able to solve the problem, nearly!!!

I think I was really on the wrong track!

Now I added the following code in my patent view:

<%params = {:watchedfamily => {:Prio_No => “666666”, :title =>
“Please”, :watchedmembers_attributes => [{:Pub_No => “Test1”},
{:Pub_No => “Test2”}]}} %>
<%Watchedfamily.create!(params[:watchedfamily]) %>

This is creating a new record with two nested records, exactlly what I
wanted. Only problem is now: HOW TO FIRE THIS WITH A BUTTON OR LINK???

Cheers

OK again I got it:

<%= button_to “Show”, :controller => “watchedfamilies”, :action =>
“create”, :watchedfamily => {:Prio_No => “X5x5x5x5”, :title =>
“Please”, :watchedmembers_attributes => [{:Pub_No => “yyy1”}, {:Pub_No
=> “zzz2”}]} %>

On Apr 27, 2011, at 9:44 AM, Sebastian wrote:

<%Watchedfamily.create!(params[:watchedfamily]) %>

This is creating a new record with two nested records, exactlly what I
wanted. Only problem is now: HOW TO FIRE THIS WITH A BUTTON OR LINK???

You need to re-think this entirely. The fact that you are calling a
Model method directly in a view should be a strong whiff of Code
Smell, and you need to consider how to make this a link to a REST
(create) method in your WatchedfamilyController rather than what you
have here. Getting the result back into your Patent view is an
exercise in routing and maybe Ajax, but what you have done in this
view shouldn’t work, or maybe shouldn’t be tried, even if you can get
it to work part-way.

Walter

Thanks for the reply!

I am not quite sure what you meant with ‘calling a Model method
directly’, probably this one, or?
<%Watchedfamily.create!(params[:watchedfamily]) %>

So I already changed my code as you can see below. Is that still Code
Smell or is that better?

<%= button_to “Save Patent”,
:controller => “watchedfamilies”,
:action => “create”,
:watchedfamily => {
:Prio_No => @Prio,
:title => @title.join(","),
:watchedmembers_attributes => @fam_pubs
}%>

There is another problem I found: If I use my above code to send more
data with one click to my database I get an “URI Too Large” error. How
can I avoid that? Or how can I store a lot of data without a large
URI???
My @fam_pubs array is very large!!!

Sebastian

Thank you!

I am still having the problem that the URI gets too large if I want to
send to much data to the database. How can I avoid this?

Can I maybe call my @fam_pubs variable in the create method of my
watchedfamilies controller, so that it is not needed to send it with
the URI?

If yes how would that look like? My create method is still the
standard one:

def create
@watchedfamily = Watchedfamily.new(params[:watchedfamily])
respond_to do |format|
if @watchedfamily.save
format.html { redirect_to(@watchedfamily, :notice =>
‘Watchedfamily was successfully created.’) }
format.xml { render :xml => @watchedfamily, :status
=> :created, :location => @watchedfamily }
else
format.html { render :action => “new” }
format.xml { render :xml => @watchedfamily.errors, :status
=> :unprocessable_entity }
end
end
end

Cheers,
Sebastian

Sebastian wrote in post #995486:

I am not quite sure what you meant with ‘calling a Model method
directly’, probably this one, or?

Watchedfamily is your Model in the example below, ‘create!’ is the
method called on it and ‘(params[:watchedfamily])’ is what you are
passing to that method.

<% Watchedfamily.create!(params[:watchedfamily]) %>

So I already changed my code as you can see below. Is that still Code
Smell or is that better?

Read this article: Code Smell

<%= button_to “Save Patent”,
:controller => “watchedfamilies”,
:action => “create”,
:watchedfamily => {
:Prio_No => @Prio,
:title => @title.join(“,”),
:watchedmembers_attributes => @fam_pubs
}%>

Yes you were right! I was definitely on the wrong track!

The URL really helped to understand how to create nested active
records.

I still have a big problem. I have two methods in my controller SHOW
and SAVE.

In the show method I extract a lot of data from an XML into a hash
variable. In the save method I want to store that variable in the
database. The problem is that my @hash variable is only available in
the first method.
How can I access a variable from one method to another? Is session or
flash a good idea for that, I don’t need that data anymore after
saving to db.

Simplified methods look like this:

class PatentController < ApplicationController
def show #This method has more than 50 lines code in reality
@hash = REXML::Document.new xmlfile
end

def create
title123 = params[:title]
pub = @hash
params = {:watchedfamily => {:Prio_No => pub, :title =>
title123, :watchedmembers_attributes => pub}}
@watchedfamily = Watchedfamily.new(params[:watchedfamily])
end
end

Cheers,
Sebastian

Or is it better to create that @hash directly in the needed method,
like this:

def create
@hash = REXML::Document.new xmlfile
title123 = params[:title]
pub = @hash
params = {:watchedfamily => {:Prio_No => pub, :title =>
title123, :watchedmembers_attributes => pub}}
@watchedfamily = Watchedfamily.new(params[:watchedfamily])
end

Or put all the ‘extract data from XML code’ into a model and just call
the model where I need it?

The problem is that I don’t know exactly what I should put in a model
and what in a controller.

Sebastian

I create the hash as mentioned in my preivious post and that is
working as intended.

Thank you for your replies, that gave me the right direction!

Sebastian

Sebastian wrote in post #995494:

Thank you!

I am still having the problem that the URI gets too large if I want to
send to much data to the database. How can I avoid this?

What do you mean by ‘the URI gets too large’? If you are running Rails
3, I suggest you read more on nested form attributes when dealing with
active record objects: