Creating and deleting instance variables - ruby-on-rails

In file index.html.erb, I have code that prints some properties of each element of #calender_items:
<% #calender_items.each do |calender_item| %>​
...
<td><%= calender_item.date %></td>
...
<% end %>
The instance variable is assigned by this line in a controller:
#calender_items = CalenderItem.all
If I comment out the this line, index.html.erb file still functions. Can someone give me any hints on why I can still access the instance variable even though it is no longer assigned? When do instance variables get destroyed?

Check for before_filters that could set the variable for some actions before firing them.
Check if the action you are calling are actually the action that you removed the instance variable. Ex.: controller/index calls Controller def index action.
Check the ApplicationController, maybe the variable is being set there too.
Instance variables only live through requests, so if you commented the code, it should not work.

Related

Rails Controller Confusion

this is my first post.
I'm brand new to Rails and I'm attempting to learn how to use it. To be clear, I have a brushing familiarity with Ruby. I'm pretty sure I get the MVC structure, but I'm having trouble understanding certain behaviors I'm experiencing.
Just in case anyone learned from the same source, I'm watching Derek Banas explain it. He explains the thing I'm having trouble with around 16:20. https://www.youtube.com/watch?v=GY7Ps8fqGdc
On to specifics- So I placed this line in my routes.rb file:
match':controller(/:action(/:id))', :via => :get
and I created an instance variable in the controller using this:
def sample
#controller_message = "Hello From The Controller"
end
And in a sample view I created, I call on the "controller_message" variable like this:
<%= "#{#controller_message}" %>
And it works on that one view half the time. Now from what I understand, I should see "Hello From The Controller" anywhere that line of code is placed in a view, right? Maybe I just don't understand how this functions, but I made other view files in the same directory in an attempt to see how controllers pass data to views. They load and everything, but I'm not getting the message from the controller. Sometimes, seemingly inconsistently, the controller message won't even display on the first view where it worked originally, especially if I navigate around the site a little. To get it to display that message again, I have to restart my server.
So am I just misunderstanding how MVC works, or is my software glitching (unlikely, I know), or what? I'm so confused.
I've heard so many great things about this community. Thanks in advance to anyone willing to help me. I'm so stressed out.
The #{} in <%= "#{#controller_message}" %>is string interpolation. The usual convention of displaying an instance variable in a view is simply <%= #controller_message %>
The variable #controller_message, declared in the sample method, makes that variable available to the view associated with that method. By default, rails will look for a corresponding view file that has the same name as the controller method, so in this case it will look for a view called sample.html.erb in the app/views/your_controllers_name folder
Well, to clarify things (because your question is a little vague): rails does a lot of stuffs behind the scene, like relating controller's name with view's name. That is why, in most case, you don't invoke a view to be render in controller's method (Rails does that to you based on file's name). So, would make sense the variables declared in a controller method be displayed only in the view with the same name as the controller method called. If you want to display a variable in a view that is not related with the controller method, you should invoke that view with methods like Render and Redirect, and pass the variables as arguments to those methods.
I.g:
other.controller
def edit
render "/another_view_folder/example.html.erb", #variable_to_be_displayed
end
Another thing:
<%= #controller_message %>
This is enough to display the variable. The way you were doing was Interpolation (use to concatenate variable with strings).
I hope I can help you!
Rails will implicitly render a view file if it is found in the view path.
So given:
# config/routes.rb
get 'foos/bar'
# app/controllers/foo_controller.rb
class FoosController < ApplicationController
def bar
#controller_message = 'Hello'
end
end
Rails will attempt to find the file bar.html.erb in app/views/foos when we request /foos/bar. If we want to render another view we need to tell rails to render it explicitly.
class FoosController < ApplicationController
def bar
#controller_message = 'Hello'
render 'some_other_view' # renders app/views/foos/some_other_view.html.erb
# or
render 'some_other_folder/some_other_view' # renders app/views/some_other_folder/some_other_view.html.erb
end
end
Now from what I understand, I should see "Hello From The Controller" anywhere that line of code is placed in a view, right?
No. Lets say you add another controller and view.
# config/routes.rb
get 'people', to: 'people#index'
# app/controllers/people_controller.rb
class PeopleController < ApplicationController
def index
end
end
# app/views/people/index.html.erb
<h1>The message is: <%= #controller_message %></h1>
It will just render The message is:. Since PeopleController does not set the instance variable #controller_message. Ruby will not raise an error if you reference an unassigned instance variable.
The way to reason about this is that the controller in Rails packages all its instance variables and passes them to the view context so that we can use them in the view.
After the controller has finished rendering it sends the rendered template and the program exits*. Instance variables, local variables etc, do not carry over to the next request.

Use a variable created in a loop in other files - Ruby on Rails

I was wondering how I could use a variable that was created in a loop in other files. For example, I have this loop in my views :
<% for #p in #posts %>
<%= #p.content %>
<% end %>
How could I use #p in a method that I created in my controller? Thank you in advance!
Variable that are created in loops, are technically created inside a block. The variables that are created in a block, are accessible to that block. Please read this https://www.sitepoint.com/understanding-scope-in-ruby/
I am not sure why would anyone wants to use a variable that is created in a view in a controller, it's the reverse, YOU SHOULD use the variable that is created in the controller in views
Since you have tagged global variables in the question, if you want to use them anyways, use $p instead of #p

Can't call instance method from index view

I'm trying to call method (instance method) which I have defined in the controller from the index.html.erb view.
records_controller.rb:
def calc_cell_balance
4
end
index.html.erb:
<% #records.each do |r| %>
<%= r.calc_cell_balance %><br>
<% end %>
I get this error:
undefined method `calc_cell_balance' for #<Record:0x35d18d8>
I don't want to make it a class method because it's bad design.
If I put the method definition in record.rb (the model), it's working.
I'm not sure what I'm doing wrong, since it's wrong to access the model from the view, but it's the only thing working.
How can I resolve this?
Thanks.
You put an instance method in your controller, RecordsController, but you are trying to call the method on an instance of the Record class. This doesn't make sense at all. Your #records are all Record instances. You would have to do something like:
RecordsController.new.calc_cell_balance
BUT DON'T DO THAT! Your controller is there to just direct what needs to be done, and shouldn't have methods that are called outside of the controller instance itself.
Your method probably belongs in the Record model, or maybe in a helper. It is not at all wrong to access the model from the view. That's the main thing that people do. If you really wanted to not be calling any methods from the view, you could try to gather up all the information in the controller like this:
#records = Record.all
#records_calc_cell_balance = #records.collect(&:calc_cell_balance)
And then you have parallel arrays of data, but that's just silly. Calling model methods from the view is fine. Or, if you feel the method is too view-centric (like maybe you want a method to tell you what CSS class to use), put that in a view helper, which is what it's for.

need to pass parameter from controller to .html.erb file

My controller code:
def description
product = #products.find(params(:id))
end
This is in the controller and I have to pass the product variable to description.html.erb. How can I do this?
It is giving me an ArgumentError in StoreController#description.
In general the way variables from the controller get passed to the views is by assigning them as an instance variable, which are variables defined with an # before it, e.g #products. If you want the product variable to be passed along, it has to be set as #product, like so:
#product = #products.find ...
In this particular case, you are getting an error raised before your view even is called. The only line in your controller action is throwing this.
Make sure that #products is actually being set. It's not being set in the #description method, so is it being set in a before_filter here? Is #products able to call #find? In Rails we often only see a model calling this method, e.g Product.find(params[:id]).
Further more, I see that you're accessing your params hash with regular brackets instead of square brackets. In Ruby you use square brackets. This alone may be what's causing the error. Try changing that to:
#product = #products.find(params[:id])
You can pass variables from controller to views using #
example in controller :
#my_var = 'toto'
in view
<%= #my_var %>

Instance variable not being recognized by its view

Can anyone think of a reason why an instance variable declared in the controller would not be recognized by its view?
Controller looks something like this:
class UsersController < ApplicationController
...
def show
#questionshow = session[:profilequestioncapture]
#user = User.find(params[:id])
#question = Question.where("id = ?", #questionshow).first
...
And the view: (show.html.erb in the users directory:)
...
<dl class="dl-horizontal">
<dt>Headline</dt>
<dt>Description</dt>
<dt>Budget</dt>
<dd><%= #question.headline %></dd>
<dd><%= #question.description %></dd>
<dd><%= #question.currency %>&nbsp<%= #question.budget %></dd>
</dl>
....
-the session correctly populates the #questionshow instance variable. It only contains the id, and this gets correctly passed to #question.
-here's what's strange: <%= #user.xxxx %> gets correctly formatted and displayed, whereas anything with <%= #question.xxx %> does not.
-and here's what's even stranger. If I comment out #user in the controller the record is still correctly displayed in the view, so it's effectively ignoring what's in the controller (but I can't figure out why)
-And yes I've checked I'm looking at the right controller & viewer.
Are you sure that session[:profilequestioncapture] is not nil?
#question is an ActiveRecord::Relation object. unless you call .first on it, you'll have errors when you try to call some of the question attributes to it. and that will also be true if, as stated by one of the answers, session[:profilequestioncapture] is nil
First I think that the where scope will give you an ActiveRecord::Relation (which gives an array), not a record. Since you want to find by id I would suggest
Question.find(session[:profilequestioncapture])
Most probably you will want to rescue ActiveRecord::NotFound exception and either set a default question or change the behavior.
Are you using Draper or Presenters?
Can you double check your #question actually has data?
As for your #user behind populated even if commented out:
Check for caching issues
Check for before_filter actions that could populate it for you.
I found the solution, but it's left me a bit bewildered. I was not defining the same instance variable attached to my Questions model across all actions in the same controller. So in Show is was #question whereas in Create it was (for example) #yyyquestion and in Update I had used something else (e.g. #yyyquestion). I have no clue why this would cause the error and why the instance variable would be populated in the controller but not in the View. I think there is more to this story...

Resources