undefined method `stringify_keys' for false:FalseClass - ruby-on-rails

Gives me that error with this code
module Spree::Admin::ProductsHelper
def stores_checkbox
capture do
Spree::Store.all.each do |store|
concat hidden_field_tag "product[store_ids][]", store.id, #product.stores.include?(store)
end
end
end
end
But it was ok with this one....
module Spree::Admin::ProductsHelper
def stores_checkbox
capture do
Spree::Store.all.each do |store|
concat check_box_tag "product[store_ids][]", store.id, #product.stores.include?(store), :style => "display: none;"
end
end
end
end
What's the problem?

Change this:
hidden_field_tag "product[store_ids][]", store.id, #product.stores.include?(store)
to:
hidden_field_tag "product[store_ids][]", store.id
The issue: hidden_field_tag is expecting a hash as it's last parameter, but you are passing in a false (boolean).
The change I suggest will add the product store_id as a hidden field on the form, with it's value set to store.id.
You can read more about the hidden_field_tag here.

Your third parameter needs to be an options hash. check_box_tag has a different method signature, where the third parameter is the initial checked state, and the options hash is the fourth parameter. Whenever you see that stringify_keys error, your first guess should be that a hash was expected, and you provided something else. Just get rid of your third parameter, and it should work fine.

Related

How to make value attribute in the select option tag to have url's in rails

I want value attribute in the select option menu to contain url's and on click should take to the particular path.I am using helper method to build the path
Code:
<%= select_tag :account, options_from_collection_for_select(Account.all,build_path_for_airline(id),"name") %>
helper:
def build_path_for_airline(id)
new_path = Rails.application.routes.recognize_path(request.path)
new_path[:airline_id] = id
new_path
end
Unfortunately its not working as expected, Can anyone let me know what I am missing here?
According to the documentation, the value_method parameter is exactly that, a method. You can't use an arbitrary block of code and expect it to work.
You should implement your build_path_for_airline as an helper method in your model class, and use that method in the options_from_collection_for_select call.
# app/models/account.rb
class Account
# ...
def airline_path
# Build the airline path for the current account
end
end
# app/views/...
<%= select_tag :account, options_from_collection_for_select(Account.all, :airline_path, :name) %>
Richard-Degenne's answer is correct, but there's an alternative to putting the method in your model. options_from_collection_for_select can also take a lambda for its value_method argument:
<%= select_tag :account, options_from_collection_for_select(
Account.all,
->(account){ build_path_for_airline(account.id) },
"name")
%>

Controller, Model, View. Confusion with passing params

I have a simple self method defined in my model.
def self.search(name, type)
#handle name
#handle type
end
My confusion is with regards to the view & controller. Passing the correct values (or using the correct syntax).
In the view, a simple form.
<%= form_tag(index_path, method: :get) do %>
<%= label_tag :type, 'Type' %>
<% type_array = ["Foo", "Foo_One", "Foo_Two", "Foo_Three"] %>
<%= select_tag :type, options_for_select(type_array, selected: params[:type]), include_blank: true %>
<%= label_tag :name, 'Name' %>
<% name_array = ["Foo", "Foo_One", "Foo_Two", "Foo_Three"] %>
<%= select_tag :name, options_for_select(name_array, selected: params[:name]), include_blank: true %>
<%= submit_tag "Filter" %>
<% end %>
Confusion One
Under options_for_select, should it be select_tag :search or select_tag :type? Should it be selected: params[:search] instead??
In the controller
def index
#foo = Foo.all
#variation 1 that i tried
#foo = #foo.search(params[:search]) if search(params[:search]).present?
#variation 2 that i tried
#foo = #foo.search(params[:name,:type]) if search(params[:name,:type]).present?
#variation 3 that i tried
#foo = #foo.search(params[:name][:type]) if search(params[:name][:type]).present?
end
Confusion Two
Variation 3 kind of makes the most sense to me. But i dont see the self.search getting called. Also it throws an error (no implicit conversion of Symbol into Integer).
I'm not sure if the error is with my forms too?
Clearly i'm not very proficient with knowing where to pass the params and "collect" them. I've tried reading the ruby documentation but had a hard time understanding it.
I think the bigger picture would be, whats the proper syntax (or way to collect arguments) in a form for a method?
Confusion 1: It doesn't matter what the select_tags are called in your case as you don't seem to have it tied to an actual model attribute, but 'name' and 'type' are quite confusing simply as there are HTML attributes name and type on input fields. Still, it will still work the way you have done it and the 'selected' options look just fine.
Confusion 2: You need to access them individually from the params hash:
#foo.search(params[:name], params[:type]) if params[:name].present? || params[:type].present?
However, you have defined it as a self method as so:
class FooClass
def self.search(name, type)
# blah
end
This means you can't access it on an instance of the class, i.e #foo.search, you would call it from the class itself:
FooClass.search(params[:name], params[:type]) if params[:name].present? || params[:type].present?
If on the other hand you didn't have the 'self', as so:
class FooClass
def search(name, type)
# blah
end
The you could do:
#foo = FooClass.new
#my_var = #foo.search(params[:name], params[:type])
First off change self.search to just search because your index method in your controller is using an instance of your Foo model. when you do self.method that is a class level method and essentially works without having to create an instance of your class, which in this case is your Foo class.

If, else dynamic statement logic

Can someone explain the logic behind this code?(This is the correct code btw)
<% if #request.query['first_name'] && !#request.query['first_name'].empty? %>
Welcome! <%= #request.query['first_name'] %>
<% else %>
Hi! What is your name?
<% end %>
My intuition is to write the following instead:
<% if #request.query.inspect['first_name'].empty? %>
Hi! What is your name?
<% else %>
Welcome! <%= #request.query.inspect['first_name'] %>
<% end %>
I am trying to have a user form where people can input their names, when there is no input yet the text above the form says "Hi! What is your name?" when there is an input it has a message saying "Welcome! *User_name*"
The first block of code is not intuitive to me, the second one would make more sense.. ANy advice on how to understand the code?
Your intuition is correct, though you need an alternative to empty?. Rails adds a few different methods you can use:
blank? returns true if the receiver is nil, an empty array, string, or hash, or a string with only whitespace.
present? returns true if blank? is false. So your condition could be:
<% if #request.query['first_name'].present? %>
Welcome...
(I find it's always more intuitive to start with the positive condition - it would work just as well to check blank?).
Edit: It's pretty likely you can skip the query method entirely if all you expect there is either a string or nil. Just use:
<% if #request.query['first_name'] %>
You need to check if it's nil before you can check if its empty, because you are checking a Hash#empty?
irb(main):001:0> nil.empty?
NoMethodError: undefined method `empty?' for nil:NilClass
from (irb):1
irb(main):002:0> {}.empty?
=> true
The code checks for hash key existence, then check if the value of the hash is present. This action can be done in one check using:
#request.query.try(:[], 'first_name').empty?
You can avoid the first condition inside the if statement by transforimng nil into an empty string. I don't know if that is what you meant to do but you almost had.
First, you shouldn't call inspect in the hash because it will transform the entire thing into a 'complex' string. What you want to do turn only the value inside the first_name option, because in that case if the name exists it will still be the same, and if it doesn't, it will be turned into "nil".
Secondly, the method inspect isn't the best choice here, because the returned string will never be empty, given that nil.inspect => "nil". What you should use is the method to_s, wich will behave like this when applied to nil: nil.to_s => "".
Finally, you could update your code to:
<% if #request.query['first_name'].to_s.empty? %>
Hi! What is your name?
<% else %>
Welcome! <%= #request.query['first_name'] %>
<% end %>

Rails methods with default values

I have helper function in application_helper.rb file:
def nested_attributes(attributes, cn = controller_name.classify)
attributes.map do |attribute, sub_attributes|
content_tag(:ul) do
content_tag(:li, :id => cn+"[#{attribute.id}]") do
raw(attribute.name+nested_attributes(sub_attributes))
end
end
end.join.html_safe
end
and then I calling it from view:
<%= nested_attributes #categories.arrange, 'baget_category_id' %>
But when I check result, I got Controller name (Which is default value) instead of 'baget_category_id'. When I remove default value, i got an error: wrong number of arguments (1 for 2). What I'm doing wrong?
Your problem seems you have to pass cn to recurring call:
raw(attribute.name+nested_attributes(sub_attributes, cn))

optional local variables in rails partial templates: how do I get out of the (defined? foo) mess?

I've been a bad kid and used the following syntax in my partial templates to set default values for local variables if a value wasn't explicitly defined in the :locals hash when rendering the partial --
<% foo = default_value unless (defined? foo) %>
This seemed to work fine until recently, when (for no reason I could discern) non-passed variables started behaving as if they had been defined to nil (rather than undefined).
As has been pointed by various helpful people on SO, http://api.rubyonrails.org/classes/ActionView/Base.html says not to use
defined? foo
and instead to use
local_assigns.has_key? :foo
I'm trying to amend my ways, but that means changing a lot of templates.
Can/should I just charge ahead and make this change in all the templates? Is there any trickiness I need to watch for? How diligently do I need to test each one?
I do this:
<% some_local = default_value if local_assigns[:some_local].nil? %>
Since local_assigns is a hash, you could also use fetch with the optional default_value.
local_assigns.fetch :foo, default_value
This will return default_value if foo wasn't set.
WARNING:
Be careful with local_assigns.fetch :foo, default_value when default_value is a method, as it will be called anyway in order to pass its result to fetch.
If your default_value is a method, you can wrap it in a block: local_assigns.fetch(:foo) { default_value } to prevent its call when it's not needed.
How about
<% foo ||= default_value %>
This says "use foo if it is not nil or true. Otherwise assign default_value to foo"
I think this should be repeated here (from http://api.rubyonrails.org/classes/ActionView/Base.html):
If you need to find out whether a certain local variable has been assigned a value in a particular render call, you need to use the following pattern:
<% if local_assigns.has_key? :headline %>
Headline: <%= headline %>
<% end %>
Testing using defined? headline will not work. This is an implementation restriction.
In my case, I use:
<% variable ||= "" %>
in my partial.
I don't have idea if that is good but for my is OK
I know it's an old thread but here's my small contribution: i would use local_assigns[:foo].presence in a conditional inside the partial.
Then i set foo only when needed in the render call:
<%= render 'path/to/my_partial', always_present_local_var: "bar", foo: "baz" %>
Have a look at te official Rails guide here. Valid from RoR 3.1.0.
This is a derivative of Pablo's answer. This allows me to set a default ('full'), and in the end, 'mode' is set in both local_assigns and an actual local variable.
haml/slim:
- mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full')
erb:
<% mode ||= local_assigns[:mode] = local_assigns.fetch(:mode, 'full') %>
I think a better option that allows for multiple default variables:
<% options = local_assigns.reverse_merge(:include_css => true, :include_js => true) %>
<%= include_stylesheets :national_header_css if options[:include_css] %>
<%= include_javascripts :national_header_js if options[:include_js] %>
Ruby 2.5
Erb
It's possible, but you must to declare your default values in the scope.
VARIABLE the word for replacement.
# index.html.erb
...
<%= render 'some_content', VARIABLE: false %>
...
# _some_content.html.erb
...
<% VARIABLE = true if local_assigns[:VARIABLE].nil? %>
<% if VARIABLE %>
<h1>Do you see me?</h1>
<% end %>
...
More intuitive and compact:
<% some_local = default_value unless local_assigns[:some_local] %>
If you do not want to pass local variable to partial each time you call it you do this:
<% local_param = defined?(local_param) ? local_param : nil %>
This way you avoid undefined variable error. This will allow you to call your partial with/without local variables.
A helper can be created to look like this:
somearg = opt(:somearg) { :defaultvalue }
Implemented like:
module OptHelper
def opt(name, &block)
was_assigned, value = eval(
"[ local_assigns.has_key?(:#{name}), local_assigns[:#{name}] ]",
block.binding)
if was_assigned
value
else
yield
end
end
end
See my blog for details on how and why.
Note that this solution does allow you to pass nil or false as the value without it being overridden.

Resources