0

I have this simple rails code and something weird is happening. As you can see params.nil? is true and it's still calling the else part. What am I missing here?

Pry Session

     5: def build_resource
     6:   binding.pry
     7:   if params.nil?
     8:     model_class.new
     9:   else
 => 10:     params = params.merge(dealer: {})
    11:     model_class.new(dealer_params)
    12:   end
    13: end

[3] pry(#<Admin::DealersController>):1> params.nil?
true
luisenrike
  • 2,742
  • 17
  • 23
  • This code seems very odd. You should test for `nil?` once and once only. The `unless` on line 10 is pure paranoia. Also `params` is really not supposed to be `nil`, but it can be `empty?`. I have a feeling the `params=` part here is the issue since you're not supposed to assign back to `params`, that creates a variable. – tadman May 04 '18 at 18:32
  • What you probably want here is `params[:dealer] = { }`. Manipulating `params` is fine, but reassigning to it is bad. – tadman May 04 '18 at 18:33
  • Yeah, I removed the `unless` part. – luisenrike May 04 '18 at 18:33
  • If I do `params[:dealer]` I get this: `undefined method []' for nil:NilClas` – luisenrike May 04 '18 at 18:34
  • Are you running this in a controller context? If so, `params` should always be something unless it got trashed somehow by some renegade code. At the absolute least `params` contains `:controller` and `:action` keys. – tadman May 04 '18 at 18:35
  • Yes, I'm running it in a controller context. I know that `params` shouldn't be `nil`, but still, why `pry` is showing that `params.nil?` is true? – luisenrike May 04 '18 at 18:36
  • What `pry` is showing is just plain odd. I'd try and figure out why. – tadman May 04 '18 at 18:43
  • I just found out that there is a variable called `@_params` that has the `controller` and `actions` params – luisenrike May 04 '18 at 18:46
  • After I removed `binding.pry` everything works, I am going to create an issue in the pry's repository. – luisenrike May 04 '18 at 18:50
  • Why the downvote? – luisenrike May 04 '18 at 20:00
  • `params = params.merge(dealer: {})` might be the problem. If you want to create a variable `params` there is no issue, but you have to call the method by `self.params` in this scenario. Thus resulting in `params = self.params.merge(dealer: {})`. – 3limin4t0r May 04 '18 at 21:42
  • See the ruby docs about this behavior: https://ruby-doc.org/core-2.5.0/doc/syntax/assignment_rdoc.html#label-Local+Variables+and+Methods – 3limin4t0r May 04 '18 at 21:50
  • Awesome, thanks for the link. – luisenrike May 05 '18 at 01:39

2 Answers2

1

No, Its not a pry issue. You just cant reassign params to params. Try using different variable. This should work fine.

You can use as

dealer_params = params.merge(dealer: {})

updated answer

Digging Deeper inside Rails. Have a look at this.

class Parameters

cattr_accessor :permit_all_parameters, instance_accessor: false, default: false

cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false

.....
end

Simple Explanation: params are responsible for carrying value which you permit inside your controller, but its resigning it will return false or nil. You can study about these topics in dept you get to know.

https://apidock.com/rails/Class/cattr_accessor

That's why when you declare new variable the value of params => (object) is assigns to it. But when you do the same thing with params or method that return an object this will give nil.

SAME Answer: you just can't reassign params to params.

Romanch Sharma
  • 122
  • 2
  • 11
  • Actually, you **CAN** assign `params` to `params` (`self.params = self.params.merge(s: "works")`). In my code, you casn see that line hasn't been executed yet. After I removed `binding.pry` `params` wasn't `nil` anymore, I tested it with `p params` instead of `binding.pry`. – luisenrike May 04 '18 at 19:55
  • `:s/casn/can/g` – luisenrike May 04 '18 at 20:01
  • @luisenrike There's a big difference between `self.params =` and `params =` where the former calls the `params=` method and the latter defines a variable that then masks the method off. – tadman May 05 '18 at 02:38
  • @luisenrike you are taking this in wrong direction. I am just trying to help you. Let me explain it better now. – Romanch Sharma May 05 '18 at 04:12
0

So, this answer my question (https://stackoverflow.com/a/1335890):

The params which contains the request parameters is actually a method call which returns a hash containing the parameters. Your params = line is assigning to a local variable called params.

After the if false block, Ruby has seen the local params variable so when you refer to params later in the method the local variable has precedence over calling the method of the same name. However because your params = assignment is within an if false block the local variable is never assigned a value so the local variable is nil.

If you attempt to refer to a local variable before assigning to it you will get a NameError:

irb(main):001:0> baz
NameError: undefined local variable or method `baz' for main:Object
        from (irb):1

However if there is an assignment to the variable which isn't in the code execution path then Ruby has created the local variable but its value is nil.

irb(main):007:0> baz = "Example" if false
=> nil
irb(main):008:0> baz
=> nil
luisenrike
  • 2,742
  • 17
  • 23