Instance variable not being recognized by its view - ruby-on-rails

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...

Related

Elegant way to show corresponding text_field_tag value in Rails 4

So my problem is showing something that a model has in a nice and simpler way.
So what currently works?
In my viewer this works fine:
<%= text_field_tag(:first_name, (current_user.present? ? current_user : '').first_name.present? ? current_user.first_name : '') %>
However this is too long and really hard to maintain, especially when I have several more fields.
So to avoid that I made this in my controller
def user_vals(value)
if(current_user.present?)
current_user.value.present? ? current_user.value : ''
end
return ''
end
Within this controller I can call user_vals(:first_name) but get undefined methodvalue'` error. Furthermore I cannot just call
<%= text_field_tag(:first_name, #user_vals(:first_name)) %>
As I am getting some syntax error with brackets but that's not the real issue.
So my ultimate goal is to have something like this:
<%= text_field_tag(:first_name, #user_vals(:first_name)) %>
Rather than the first code I've given above. How can I achieve that?
You can use try in this case. Just write:
<%= text_field_tag(:first_name, current_user.try(:first_name)) %>
See: http://apidock.com/rails/Object/try
I would recommend to take a step back and try to use Duck Typing to solve this...
What you have right now is a current_user method. This method can return whatever object it wants if the user is not logged in, and that object can respond to whatever it wants. Here's a simplified example:
def current_user
#user || OpenStruct.new(first_name: "")
end
Note: I'm assuming #user holds the currently-signed in user... but this may be a call to super instead, or whatever else depending on your implementation.
So now, instead of branching based on what type of object is coming back from the current_user method, you can now just use the returned object without regard.
current_user.first_name # => Either the User object's first name or `""`
You can go further with this by creating e.g. a GuestUser class and having GuestUser.new returned instead of the OpenStruct above. Guestuser would be a model that is not data-base backed and could respond to any number of methods as needed.
This idea has been represented by many others as well. And using a class to prevent repeated code switching based on nil actually has a name: The Special Case Pattern. As a quick, free example, see the Guest User RailsCast. Or, if you subscribe to Ruby Tapas, be sure to check out episode 112: Special Case. This topic, and many others, are also covered in depth in Avdi Grimm's excellent book: Confident Ruby, which I highly recommend.

Creating and deleting instance variables

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.

Extra instance variable in controller is nil in view?

I have been searching through Stack Overflow for a few hours now, but none of the related questions seem to apply to my issue.
I am new to Rails, with this being my first real project, and I may be confusing the MVC setup a little. I am attempting to assign the #stars instance variable while in an action of the searches_controller.rb:
def create
#search = Search.new(params[:search])
tempstr = searchstr(#search)
#stars = Star.where("tempstr", :limit => 100)
end
#search is created fine, being a complex search with varying parameters. tempstr is just a simple string container for the results of searchstr(#search), which is a quick method for converting the search parameters into a MySql-relevant string (which seems to be easier than trying to use the .where helper normally, in this case). I'm sure I can just put searchstr(#search) directly into the .where, but I split them up for now so I can inspect the elements as they pass through.
Anyways, the issue comes up when I try to call #stars in the show.html.erb view. Even with something as simple as this:
<% #stars.each do |star| %>
<%= display stuff %>
<% end %>
I get an error saying 'each' is not a method of nil:NilClass. So, I changed it to the following to see if #stars was nil:
<%= #stars.inspect %>
Sure enough, #stars is nil. However, when I add this line to my controller to check #stars there:
return render #stars.each
I see that the variable is filled with the correct star objects from the Star.where(), just as I had intended. A quick .inspect shows the variable is not nil, when in the controller.
So, I am unsure why the view is receiving it as nil if it has been defined in the controller just fine. I wouldn't be surprised if it was me misunderstanding how MVC works, though. The Star class was defined in the Star model, but maybe it is because I am trying to access it from the Searches controller, and thus it isn't initialized for the view?
Should I be going about doing this some other way? I attempted to use a local variable (using stars instead of #stars), but then the view says "Undefined local variable or method 'stars'".
Any help would be much appreciated, I have already wracked my brain for hours creating the complex search and parsing the star file data into the database, so I'm a bit burnt out. I can supply more information if requested, I'm not sure what else would be helpful in providing an answer.
You are setting #stars in the create method, but the view you are talking about is show.html.erb. Try setting #stars in the show method too. Something like this:
def show
#search = Search.find(params[:id])
tempstr = searchstr(#search)
#stars = Star.where("tempstr", :limit => 100)
end
If this does not help you, please show the rest of you controller actions, so we can help you better.

Way to see which rails controller/model is serving the page?

This might be a slightly odd question, but I was wondering if anyone know a Rails shortcut/system variable or something which would allow me to keep track of which controller is serving a page and which model is called by that controller. Obviously I am building the app so I know, but I wanted to make a more general plugin that would able to get this data retroactively without manually going through it.
Is there any simple shortcut for this?
The controller and action are defined in params as params[:controller] and params[:action] but there is no placeholder for "the model" as a controller method may create many instances of models.
You may want to create some kind of helper method to assist if you want:
def request_controller
params[:controller]
end
def request_action
params[:action]
end
def request_model
#request_model
end
def request_model=(value)
#request_model = value
end
You would have to explicitly set the model when you load it when servicing a request:
#user = User.find(params[:id])
self.request_model = #user
There are a number of ways that I know of:
First you can do rake routes and check out the list of routes.
Second you could put <%= "#{controller_name}/#{action_name}" %> in your application.html.erb and look at the view to see what it says. if you put it at the extreme bottom you'll always get that information at the bottom of the page.
The controller can be accessed through the params hash: params[:controller]. There isn't really a way to get the model used by a controller though, because there is no necessary correlation between any controller and any model. If you have an instance of the model, you could check object.class to get the model's class name.

Passing a model attribute to a Rails view using redirect_to

I'm trying to pass a model attribute to a view, after successfully setting it to a new value from inside an action in my controller. But this variable is always nil by the time it gets to the view, so I can't use it to conditionally display stuff. I should add that this attribute is not a field in the database. What am I missing/doing wrong?
Here is the code in my model:
attr_accessor :mode
#getter
def mode
#mode
end
#setter
def mode=(val)
#mode = val
end
...in the controller:
#report.mode = "t"
redirect_to edit_report_path(#report)
...and in my view:
<%= build_report(#report.mode) %>
...but this helper method never gets the variable I just set in the controller. It is nil. What gives? Clearly I'm missing something basic here because this seems like it should be straightforward. Any insight would be greatly appreciated.
Thanks.
edit_report_path generates a URL with the ID of #report in it.
redirect_to essentially creates a whole new request, and goes to that URL. When it gets to edit, all it has is the ID. Usually that's fine - it looks up the object and keeps going, but of course it's not going to have the non-db field you set.
There are a couple ways to fix this. You can use :render instead to get to the edit page - then #report will have the field set.
#report.mode = "t"
render :action => edit and return
Or, you can make mode a database field.
The problem here is in the redirect_to. When you redirect somewhere else all instance variables are lost. So when you set #report.mode = "t" it sets the attribute. But when you redirect that data is lost.
I am assuming the <%= build_report(#report.mode) %> is in edit_report.html.erb and the code from when you set 'mode' is not in the edit action. If this is the case you may be able to pass the report.mode to the edit action in the url like so:
build_report(#report.mode, :mode => "t")
The problem is the redirect_to; you're returning a response to the client that causes it to redo the request with a different url. In that second request the mode isn't set because you didn't save it before wrapping up the first request.

Resources