Rails methods with default values - ruby-on-rails

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

Related

Rails: How to pass params of multiple checkbox to the model

i built this form that generate me some chebox with value like "U6", "U8" eccc
<%= form.label "Seleziona Categorie" %>
<% TeamCategory::NAMES.each do |category| %>
<%= check_box_tag 'categories_selected[]', category -%>
<% end %>
Now i have to pass the value of selected check_box to a method in my model.
Now is:
def create_tournament_team_categories
TeamCategory::NAMES.each do |name|
team_category = TeamCategory.where(name: name).first_or_create
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end
I would like to replace the TeamCategory::NAMES.each do with "selected check_box each do" and TeamCategory.where(name: name) with the value selected.
Thank you in advance
I am a newbie with Rails. What I see is that you took the part of the form to create the team, right?
For your code straight forward it could be:
<%= form.label "Seleziona Categorie" %>
<% TeamCategory::NAMES.each do |name| %> #you are looping through team category NAMES constant
<%= check_box_tag 'category_names_selected[]', name %>
<% end %>
Your form as is allows more than one category to be selected.
For the method:
def create_tournament_team_categories(category_names_selected)
category_names_selected.each do |name|
team_category = name
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end
you will probably use this method in your teams_controller.rb. In the controller, you should be able to retrieve from params a freshly created array of selected names with something along the lines with this.
#category_names_selected = params[:category_names_selected]
I do not know how complicated your app is so it might also be nested under ["team"][:category_names_selected] or ["team"]["category_names_selected"] in your params hash.
To see the exact structure of the params hash and adjust the equation above you can add for example require 'pry' at the top of your controller file and then but the binding.pry just after the part where your method is executed. When you restart the server and the app hits this part of the controller you should be able to see the exact structure of your params hash in the terminal.
You can then pass the array to the method that you can call in the controller. Do not forget to add :category_names_selected to the strong params in the controller. I hope this helps.
Controller on line 30
def create
#tournament = Tournament.new(tournament_params)
#tournament.sport_club = current_user.sport_club
#category_names_selected = params[:category_names_selected]
if #tournament.save
redirect_to tournaments_path, notice: 'Torneo creato con successo'
end
end
Method create_tournament_team_categories in the model
after_create :create_tournament_team_categories
def create_tournament_team_categories(category_names_selected)
#category_names_selected.each do |name|
team_category = name
self.tournament_team_categories << TournamentTeamCategory.create(team_category: team_category)
end
end

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.

undefined method `stringify_keys' for false:FalseClass

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.

Unable to access Method with argument list in View Page defined in Model page in Rails 3

app/views/users/doc_request.html.erb :
<% #docs.each do |doc| %>
<%= link_to 'Approve', User.activate_doctor(doc) %>
<% end %>
app/Model/user.rb :
def self.activate_doctor(doc)
doc.active = 1 #simply setting the value of one column to 1.
end
it's throwing error
NoMethodError in Users#doc_request
Showing /home/ajay/Desktop/10th Spet/app/views/users/doc_request.html.erb where line #16 raised:
undefined method `model_name' for Fixnum:Class
Am I right, that "active" is an attribute of user? If yes, I would change that to an instance method.
Change the line in the view to:
doc.activate_doctor
And in the model
def activate_doctor
self.active = 1 # if the colum is an integer
self.active = true # if the column is a boolean
self.update_attribute(active, 1) # if you want to update the value directly
end
Try to write in your model:
use doc.activate_doctor
def activate_doctor
update_attributes(:active => true)
end
so that it will save the updated value. I am assuming active is a boolean field.

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