railstutorial where is debug information coming fr

2019-04-04 20:01发布

问题:

In chapter 7 I'm getting the following output with

--- !ruby/hash-with-ivars:ActionController::Parameters
elements:
  controller: static_pages
  action: home
ivars:
  :@permitted: false

could someone explain where the hash-with-ivars is coming from and what ivars: :@permitted: false means?

回答1:

Interesting question! I searched all library sources of a rails project for 'hash-with-ivars' and only a single place came up: the psych ruby library for (de-)serializing arbitrary objects to and from YAML. Specifically, these are links to the source code for reading and writing this YAML structure.

In Chapter 7 of the Rails Tutorial, this output comes out as the output of the debug(params) command that you are instructed to put in a template. The debug command apparently calls the psych library to show a readable representation of the object (params in this case).

Now, params - the universal Rails data structure to hold parameters passed from URLs or forms - is an object that behaves like a Hash but is not pure hash: it is an instance of class ActionController::Parameters which is a subclass of Hash, let's see the class definition:

module ActionController
  # ...
  class Parameters < ActiveSupport::HashWithIndifferentAccess
    # ...
  end
end

while HashWithIndifferentAccess is a direct subclass of Hash.

As a subclass of Hash, the params object can hold other data besides the hash itself and this is what psych actually supports when trying to print the object in a readable form. Besides printing all the hash elements (under the elements key), it tries to also list all instance variables of the object and prints it under the ivars key.

So, all in all, this debug print simply says that the object debugged is an instance of the ActionController::Parameters class, which is a subclass of Hash, that besides it's hash elements has also a @permitted instance variable defined and it is currently set to false. The two elements, by the way, the controller and action are parameters used internally by Rails for routing.

When you look into the source of the class again, you will indeed find the @permitted variable right in the constructor:

class Parameters < ActiveSupport::HashWithIndifferentAccess
  # ...
  def initialize(attributes = nil)
    super(attributes)
    @permitted = self.class.permit_all_parameters
  end
end

Finally, from the documentation we can conclude that the @permitted variable holds the state of the params permission. I.e. it is set to true after the params are permitted by using the permit method:

permitted = params.require(:person).permit(:name, :age)
permitted.permitted? # this prints out the @permitted instance variable
# => true

Update: why the RailsTutorial's debug output differs

The debug output at the RailsTutorial differs a bit - it does not print ivars. Why? It is because the feature for serializing hash-with-ivars was added to the psych gem in its version 2.0.9. The psych gem is now a part of the Ruby standard library and this particular version of it has been added to the stdlib 2.3.0 preview1 version.

So, the mysteriously different output has a simple explanation: the RailsTutorial author most probably used ruby 2.2 or earlier when writing the book and this ruby version did not display instance variables in the Hash debug output yet. Actually, there are hints in the tutorial that suggest that the author used ruby 2.1.5.