简体   繁体   中英

Ruby on Rails: Initializing instance variables with helpers in view

I'm running into some type of a scope issue that's preventing instance variables from being properly initialized by helpers called from the view.

#sample_controller.rb
class SampleController < ApplicationController
  def test
  end
end

#application_controller.rb
helper_method :display 
def display
  if not defined? @display
    return @display = "a"
  else
    return @display += "a"
  end
end

#test.html.erb
<%= display %>
<%= display %>
<%= @display %>
<%= @display.reverse %>

When sample/test is displayed, it dies with an error "while evaluating nil.reverse". This is surprising because the first two calls to display should have initialized @display I would have thought. If <%= @display.reverse %> is removed the output is "a aa", indicating that the @display instance variable is getting set by the helper method, but there is no access to it in the view.

If the controller is modified so to become (with the original view code):

class SampleController < ApplicationController
  def test
    display
  end
end

The output becomes "aa aaa aa". If I make it 2 calls to display in the controller, I get, "aaa aaaa aa aa". So it seems like only the calls made in the controller will modify the SampleController instance variable, whereas calls in the view will modify an instance variable for the ApplicationController that the view has no access to.

Is this a bug in Rails or am I misunderstanding and this is for some reason intended functionality?

The context in which I ran into this bug is trying to create a logged_in? ApplicationController method that sets up an @user variable the first time it is called, and returns true or false if a user is logged in. This would not work unless I added an unnecessary call in the controller before attempting to use it in the view.

There are two @display ivars at render time, one in the controller and one in the view. The view can't access the one in the controller and vice versa. At the start of the render Rails copies all the controller ivars into the view. But at that time @display does not exist and is not copied over. In any ruby program a call to @my_undefined_ivar will return nil - which is exactly what is happening to you.

Could be confusing, here it is said another way. Rails copies ivars from the controller into the view at the start of the render. So, changes in the view's ivar are not reflected in the controller ivar and vice versa. The helper you defined lets the view invoke a method on the controller so the controller's ivar can be passed back to the view as a return value but the change to the controller ivar itself is not reflected in the other, the view's, ivar.

Just use the helper method in this case and forget about @display in the view.

I think this might be the second reserved words issue I've seen this week...

Tip: you almost never need to use the return keyword in Ruby. Also, your use of defined? is freaking me out...might be worth trying this:

  if @display.nil?
    @display = "a"
  else
    @display += "a"
  end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM