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