# Pass local variables to another controller

**URL:** <https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388>\
**Category:** Rails\
**Created:** [March 31, 2008, 6:13am UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388 "2008-03-31T06:13:40Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [March 31, 2008, 6:13am UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/1 "2008-03-31T06:13:40Z")

</div>

I’ve been beating by noob head against a wall, I’d appreciate any help  
that can be offered.

I have a view listing items with a link to append a description to  
each item. I believe I have the associations in the Models defined  
correctly (item has\_many :descriptions, description belongs\_to :item)  
to be RESTful and such…

My item view includes the following code in the \<% for item in @items  
%\>:

\<%= link\_to ‘Describe’, :controller =\> :discriptions, :action =\>  
‘new’, :locals =\> {:item\_id =\> item.id} %\>

and in the development.log file I see

Parameters: {“locals”=\>{“item\_id”=\>“2”}, “action”=\>“new”,  
“controller”=\>“descriptions”}

But I can’t seem to apply the item\_id from the items/index view to the  
object being created in the descriptions/new view.

The DescriptionsController reads

def new  
@description = Description.new  
@description.item\_id = ‘item\_id’ (I know this doesn’t work, it’s  
just the last thing I tried before calling it a day…)

BTW there is an item\_id field in the Descriptions table… I must be  
missing something in plain sight. Thanks for any guidance.

SH

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [March 31, 2008, 7:25am UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/2 "2008-03-31T07:25:15Z")

</div>

Try it like this:

Item.find(params[:locals][:item\_id]).descriptions \<\< Description.new

Or if you really want to, you can do it your way but use:  
@description.item\_id = params[:locals][:item\_id]  
but it’s two lines versus one, and you still need a save. The \<\< way  
will create the description, save it, and add it to the Item’s  
has\_many association (i.e. set item\_id on the Description object)

Really, though, you can leave off the locals too:

\<%= link\_to ‘Describe’, :controller =\> :descriptions, :action =\>  
‘new’, :item =\> item %\>

And then:

Item.find(params[:item]).descriptions \<\< Description.new

(when using an object as a hash value, i.e. in the find, Rails will  
pull out the ID for you automatically… I think that’s a relatively  
new feature… well, I don’t think Rails 1.1 was that way at least)

🙂

-Danimal

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [March 31, 2008, 8:20am UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/3 "2008-03-31T08:20:37Z")

</div>

Danimal,

Thanks for the reply… I edited the DescriptionsController to read

def new  
Item.find(params[:item]).descriptions \<\< Description.new  
end

and changed the link\_to code in the view… I got an error but saw  
that rails created a Description object with that item\_id in the  
database before the error was triggered. I think I’m missing something  
in the DescriptionsControllers ‘new’ code?

Switching gears and using @description.item\_id = params[:locals]  
[:item\_id] instead, I got the correct id passed to the Description  
object, but if the text\_field for the item\_id was removed from the  
view it was saved as nil for that object! Without the text\_field in  
the view I see in the development.log:

Parameters: {“commit”=\>“Create”, “description”=\>{“author”=\>“joe”,  
“topic”=\>“wine”}

… with the text\_field in the view I see in the development.log:

Parameters: {“commit”=\>“Create”, “description”=\>{“item\_id”=\>“3”,  
“author”=\>“joe”, “topic”=\>"wine

Ugh. Any way to get the item\_id saved without that field available for  
the user to change? Or perhaps figure out what I’m doing wrong to  
create the error following your suggestion Thanks again for any help.

SH

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [March 31, 2008, 10:40am UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/4 "2008-03-31T10:40:40Z")

</div>

Hi Danimal,  
If passing the item id from the view without an text field is what you  
need, just put a hidden\_field in the view.

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [March 31, 2008, 2:54pm UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/5 "2008-03-31T14:54:55Z")

</div>

I use a very simple and transparent method (in this app, a scenario  
has\_many unit tests):

In the show view for a Scenario, the link for adding a new Unittest just  
passes the current scenario’s ID in the params (if this looks strange, I  
use haml for my views):

%td.ctl= link\_to ‘New Unit Test’, new\_unittest\_path(:scenario =\>  
scenario\_id)

Then in the Unittest controller, see if that param is populated, if so,  
set the new Unittest’s value:

def new  
@unittest = Unittest.new  
@unittest.scenario\_id = params[:scenario] if params[:scenario]  
respond\_to do |format|  
format.html # new.html.erb  
format.xml { render :xml =\> @unittest }  
end  
end

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [March 31, 2008, 4:55pm UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/6 "2008-03-31T16:55:34Z")

</div>

@AndyV

Thank you for the explanation… you’re right that my understanding of  
what’s going on is confused, I’m new to coding and get myself stuck in  
rabbit holes then find myself trying to use :locals to solve problems,  
for example.

Your description of how the routes.rb maps the relationship between  
models by named routes is clear and intuitive. After my day job I will  
apply these changes to my project…

Thanks for the help,

SH

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [March 31, 2008, 2:55pm UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/7 "2008-03-31T14:55:59Z")

</div>

@SH

It’s important to think about the process that’s going on here. The  
language you’re using to describe the problem is a little confused and  
it might help a lot to get a bird’s eye view of what you’re doing. In  
the simplest scenario the controller instance is a very short-lived  
object that springs to life only to answer a question posed by the  
user. It’s job is to gather enough information to answer the question  
and reply in a way that the user understands… and may eventually ask  
another question. In a sense it’s part of a conversation with the  
user. In this regard you are not ‘passing local variables to another  
controller’, you are answering a user request and the user is making a  
completely new request to some other controller. It’s an important  
distinction to make because it will help keep you from thinking in  
terms of sending messages to another controller; controllers respond  
to browsers.

Specifically here the main question to ask is whether the Descriptions  
will _always_ be attached to Items. If so then you can do a few  
things that will really simplify your coding.

1. Modify your routes.rb file, nesting the descriptions resource  
inside the items resource:

map.resources :items do |item|  
item.resources :descriptions  
end

By doing this you explicitly state to the Routing system that  
descriptions belong to items. The bonus is that you get named routes  
to help you with your main issue.

1. Use the named route in your link\_to  
\<%= link\_to ‘Describe’, new\_item\_description\_path(@item) %\>

This will build a url for you that will look something like /items/15/  
descriptions/new. The advantage is that the route is created by the  
Routing system so you can’t miss. Better still, the intention of the  
code is much clearer. (As a side note, I am assuming that you got  
the :locals reference by reading some about partials… it’s not  
necessary here).

1. Code the expectation for an Item into the Description model.  
The main argument for the nested route (#1) is that the nested item  
only makes sense in the context of it’s parent. In this situation,  
the Description is only meaningful with its Item. You can/should make  
that explicit in your controller. When it responds to the request to  
make a new Description for an Item it can say so:

class DescriptionsController \< ApplicationController  
…  
def new  
@item = Item.find params[:item\_id] # Note: item\_id is created by  
the named route  
@description = @item.descriptions.build  
end

def create  
@item = Item.find params[:item\_id]  
@description = @item.descriptions.build params[:description]

```
respond_to do |format|
  if @description.save
  ...
  end
end

```

end  
end

1. Also let your new.html.erb take advantage of the named route  
\<% form\_for :item, :url=\>item\_descriptions\_path, :method=\>:post do |f|  
%\>  
…  
\<% end %\>

Here you’re going to post a new entry into the Item.descriptions  
collection (you can clean this up further if it’s a singular  
resource). The create method (above) will receive the parameters. As  
with #new, it already understands that it’s scoped to an Item and the  
named route has made sure that you got the item\_id.  
@item.descriptions.build params[:description] will build a new  
Description object using the values that the user keyed and  
automatically pop the scoping item\_id in as well (note – item\_id was  
not available to the user!).

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [April 1, 2008, 8:00pm UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/8 "2008-04-01T20:00:06Z")

</div>

@AndyV

Perfect - I got it to work using the named routes. A thing of  
beauty… Thanks

SH

---

<div class="post-metadata">

**Author:** ![shenry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbce88/32.png) [@shenry](https://www.ruby-forum.com/u/shenry)\
**Post date:** [April 2, 2008, 1:26am UTC](https://www.ruby-forum.com/t/pass-local-variables-to-another-controller/133388/9 "2008-04-02T01:26:35Z")

</div>

AndyV,

Great response. One question – what if Descriptions are not always  
attached to Items?
