Passing a hash from the model to the view

I'm trying to display a drop-down menu by using an instance variable
from a model.

THIS WORKS...

<div class="field">
  <%= f.label :duration %><br />
  <%= f.select ("duration", {"30 minutes" => "30", "1 hour" => "60"},
:prompt => "Select") %>
</div>

THIS DOESN'T WORK...

Now, I want to populate the values from the model like this
@durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}

Then in the form partial I have this
<div class="field">
  <%= f.label :duration %><br />
  <%= f.select ("duration", @durations.map {|d| [d.id, d.name]}, :prompt
=> "Select") %>
</div>

I get this error:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map

How can I initialize an instance variable or instance hash and then use
it on the form for the drop-down menu?

Leonel *-* wrote:

I'm trying to display a drop-down menu by using an instance variable
from a model.

[...]

Now, I want to populate the values from the model like this
@durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}

Then in the form partial I have this
<div class="field">
  <%= f.label :duration %><br />
  <%= f.select ("duration", @durations.map {|d| [d.id, d.name]}, :prompt
=> "Select") %>

Why not just use collection_select?

And why not use Haml?

</div>

I get this error:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map

Of course you did! The view has no access to model instance variables.
If you want to use @durations in the view, you'll need to set it in the
*controller*, not the model. Rails copies controller instance variables
to the view.

How can I initialize an instance variable or instance hash

No such thing as an "instance hash". Did you mean an instance variable
that happens to contain a Hash?

and then use
it on the form for the drop-down menu?

By setting it in the controller. If this is at all confusing, you may
want to review the Rails Guides or other basic reference.

Best,

Marnen Laibow-Koser wrote:

Why not just use collection_select?

According to
http://shiningthrough.co.uk/Select-helper-methods-in-Ruby-on-Rails "Use
select when you require a basic drop-down selection box populated with
data not sourced from a database"

And why not use Haml?

I don't know what that is

Of course you did! The view has no access to model instance variables.
If you want to use @durations in the view, you'll need to set it in the
*controller*, not the model. Rails copies controller instance variables
to the view.

I just tried it from the controller and gives me same error message.

CONTROLLER
  @durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}

ERROR
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map
Extracted source (around line #20):

17: </div>
18: <div class="field">
19: <%= f.label :duration %><br />
20: <%= f.select ("duration", @durations.map {|d| [d.id, d.name]},
:prompt => "Select") %>
21: </div>
22: <div class="field">
23: <%= f.label :cost %><br />

No such thing as an "instance hash". Did you mean an instance variable
that happens to contain a Hash?

Haha, yes, sorry, that's what I meant

Leonel *-* wrote:

Marnen Laibow-Koser wrote:

Why not just use collection_select?

According to
http://shiningthrough.co.uk/Select-helper-methods-in-Ruby-on-Rails "Use
select when you require a basic drop-down selection box populated with
data not sourced from a database"

You're right...I was thinking collection_select would work with a Hash,
but of course it won't.

And why not use Haml?

I don't know what that is

But you know what Google is, right? :slight_smile: Look it up!

Of course you did! The view has no access to model instance variables.
If you want to use @durations in the view, you'll need to set it in the
*controller*, not the model. Rails copies controller instance variables
to the view.

I just tried it from the controller and gives me same error message.

CONTROLLER
  @durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}

ERROR
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map
Extracted source (around line #20):

17: </div>
18: <div class="field">
19: <%= f.label :duration %><br />
20: <%= f.select ("duration", @durations.map {|d| [d.id, d.name]},
:prompt => "Select") %>
21: </div>
22: <div class="field">
23: <%= f.label :cost %><br />

Where in the controller are you setting the variable? Let's see the
entire controller method that you're using.

Best,

And why not use Haml?

I don't know what that is

But you know what Google is, right? :slight_smile: Look it up!

haha, thanks, already did. HAML sounds good

Where in the controller are you setting the variable? Let's see the
entire controller method that you're using.

I was setting it at the top of the controller, thinking it would
propagate to all the methods.

class ServicesController < ApplicationController
  @durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}

  def index
    @services = Service.all
    ...
end

But then I moved it inside the method.

  def new
    @service = Service.new
    @durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}
    ....

It gave me another descriptive error message that led me to fix the form
partial.

  <div class="field">
    <%= f.label :duration %><br />
    <%= f.select ("duration", @durations, :prompt => "Select") %>
  </div>

And it works now! XD

Sorry, I know this is probably very basic but I just started yesterday
my first Rails application outside of a tutorial book.

Thanks for pointing me in the right direction! :smiley:

Leonel *-* wrote:

And why not use Haml?

I don't know what that is

But you know what Google is, right? :slight_smile: Look it up!

haha, thanks, already did. HAML sounds good

Where in the controller are you setting the variable? Let's see the
entire controller method that you're using.

I was setting it at the top of the controller, thinking it would
propagate to all the methods.

class ServicesController < ApplicationController
  @durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}

Yeah, I thought you might be doing that. That won't work.

The problem is that @instance_variables are always instance variables of
self. Inside an instance method (and controller actions are instance
methods), self is an instance of ServicesController.

Outside an instance method, however, self is the class object itself!
(That is, self is the object called ServicesController, which is an
instance of class Class). Thus, you're setting the instance variable on
the wrong object.

  def index
    @services = Service.all
    ...
end

But then I moved it inside the method.

  def new
    @service = Service.new
    @durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}
    ....

It gave me another descriptive error message that led me to fix the form
partial.

  <div class="field">
    <%= f.label :duration %><br />
    <%= f.select ("duration", @durations, :prompt => "Select") %>
  </div>

And it works now! XD

Exactly! You're defining the variable in the right place, so it's
getting copied to the view.

Sorry, I know this is probably very basic but I just started yesterday
my first Rails application outside of a tutorial book.

Congrаtulations and good luck! Remember to do all development
test-first (I recommend RSpec, Cucumber, and Machinist for this), and
set up version control (preferably Git) if you haven't done so already.

Thanks for pointing me in the right direction! :smiley:

You're welcome.

Best,

Leonel *-* wrote:

CONTROLLER
  @durations = {"30 minutes" => "30", "1 hour" => "60", "1 hour 30
minutes" => "90", "2 hours" => "120"}

Where did you put this line? You're not showing any context.

ERROR
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map
Extracted source (around line #20):

17: </div>
18: <div class="field">
19: <%= f.label :duration %><br />
20: <%= f.select ("duration", @durations.map {|d| [d.id, d.name]},
:prompt => "Select") %>
21: </div>
22: <div class="field">
23: <%= f.label :cost %><br />

Which template file is this from? Guessing it's in the the context of an
edit.html.erb or new.html.erb.

Also guessing that you probably need to have that hash available to both
the edit and new pages so you will probably need to set @durations using
a before_filter:

before_filter load_durations, :only => [ :new, :edit ]

private
def load_durations
@durations = { "30 minutes" => "30",
               "1 hour" => "60",
               "1 hour 30 minutes" => "90",
               "2 hours" => "120" }
end

Also guessing that you probably need to have that hash available to both
the edit and new pages so you will probably need to set @durations using
a before_filter:

before_filter load_durations, :only => [ :new, :edit ]

private
def load_durations
@durations = { "30 minutes" => "30",
               "1 hour" => "60",
               "1 hour 30 minutes" => "90",
               "2 hours" => "120" }
end

The above was very useful too, helped me adhere to the DRY principles. I
feel like a toddler, I used to just code with PHP whatever my
imagination demanded, now I have to stop every line of code to make sure
I'm doing everything correctly lol

Thanks