Pass a parameter into collection select method for text_method - ruby-on-rails

<%= collection_select(:catgory, :id, #categories, :id, :title, {}, data: { behavior: 'category_dropdown' }) %>
In the above code I need to pass a parameter to the title method. Is there any way to do this with collection_select?
<%= collection_select(:catgory, :id, #categories, :id, (:title, #program), {}, data: { behavior: 'category_dropdown' }) %>
Edit:
Looking at the internals for collection_select the text_method. It is eventually passed to a .send method which should allow for element.send(:title, #program). However, I think the issue why I still can't pass the param is that collection select is reading (:title, #program) as two params instead of one.

Use select instead:
select "catgory", "id", #categories.map{|c| [c.title(#program), c.id]}, {}, data: { behavior: 'category_dropdown' }
Should be working.

This can be done with collection_select if your model has an existing parameter you can overwrite:
f.collection_select( :your_model_id,
YourModel.all.map{|ym| ym.name = ym.custom_name(your_parameter); ym},
:id, :name,
{:selected => #model_instance.logic},
{:class => 'your class', :other => "..." } )
For instance I do this to conditionally pluralize my model's name attribute
class MyModel < ActiveRecord::Base
DEFAULT_NAME_COUNT = 99
def pluralized_name(n = DEFAULT_NAME_COUNT)
begin
return name.pluralize(n)
rescue
end
name
end
end

Related

Multiple selected data doesn't appear

I use select2 for multiple select. My problem is, I can select multiple value from json data and I can save this data in related model columns. But when I want to update this model, the selected data doesn't appear.
some part of my json data:
{
- categories:[
- {
id:7,
name:"Eğitim Bilimleri Enstitüsü"
},
- {
id: 8,
name: "Eğitim Yönetim Teftişi ve Planlaması 1. Yarıyıl"
},
...
]
}
I have a Moodle class(it is not inheritance from ActiveRecord, just a class and it has some functions which return json data). I am wondering whether it is right approach.
in the content of my form:
<%= simple_form_for(#period) do |f| %>
...
<%= f.input :moodle_connect_ids, collection: Moodle.categories.map {|p| [ p['name'], p['id'] ] }, input_html: {multiple: true} %>
...
<% end %>
I explicitly set moodle_connect_ids to be an array in my controller:
params.require(:period).permit(..., :moodle_connect_ids => [])
in the content of my .js file:
$("#period_moodle_connect_ids").select2({
placeholder: "Moodle Dönem Bağlantılarını Seçiniz",
multiple: true,
allowClear: true
});
When I select to multiple values and save my model, the column's value looks like this:
> Period.last
=> #<Period:0x007fcf53a4d830
id: 25,
...
moodle_connect_ids: "[\"\", \"85\", \"120\"]"
...
Am I on the wrong way? Have you any suggestion?
I've figured out how to do this issue.
I've added selected option in the f.input:
selected: #period.moodle_connect_ids? ? JSON.parse(#period.moodle_connect_ids).map(&:to_i) : []
the input's last state:
<%= f.input :moodle_connect_ids, collection: Moodle.categories.map {|p| [ p['name'], p['id'] ] }, input_html: {multiple: true}, selected: #period.moodle_connect_ids? ? #period.moodle_connect_ids.map(&:to_i) : [] %>

Rails options for select send nil when no option selected

I have the following code in my rails app:
<%= select :object,
:id,
options_for_select(Hash[#object_list.map { |object| [object.name, object.id] }]),
{:include_blank => 'Please select...'},
{} %>
If no option is selected then in my controller I receive an empty string.
How can I make the options for select send 'nil' value instead?
I think you can achieve that by inserting nil in your list.
<%= select :object,
:id,
options_for_select(Hash[#object_list.map { |object| [object.name, object.id] }].merge({:0 => nil}), selected: 0) %>
You should use before_action callback for your controller.
class SomeController
before_action :prepare_params
private
def prepare_params
params[:your_param] = nil if params[:your_param].blank?
end
end

search items by category_id with select_tag drop down in rails

I have edited my first code and now it's better and cleaner thanks to #FunTimeFreddie, but the issue it's not yet properly solved. I'll come back with the right answer sooner.
In a search form I need to filter all menuitems:
1. per category
2. per category and search “query”
3. per min price && || max price
… and so on, with all possible combinations
I’ve manage to make a search in all menuitems with a “query”, min_price and max_price --all possible combinations from the search form. I can NOT manage to have the list of results of the chosen category, what am I doing wrong?
This is my model(edited):
class Menuitem < ActiveRecord::Base
belongs_to :menu_category
include Filterable
scope :newest_first, lambda { order('menuitems.created_at DESC') }
scope :last_one, lambda { order('menuitems.created_at ASC').last }
scope :search_keyword, lambda { |query|
where(["title LIKE ? or body LIKE ?", "%#{query}%", "%#{query}%"]) if query != ""
}
scope :menu_category_id, lambda { |menu_category_id|
where( "menu_category_id = ?", menu_category_id ) if menu_category_id != ""
}
scope :min_price, lambda { |price|
where("price > ?", price) if price != ""
}
scope :max_price, lambda { |price|
where("price < ?", price) if price != ""
}
end
This is my controller(edited):
class MenuitemsController < ApplicationController
def index
#menuitems = Menuitem.newest_first.filter(params.slice(:menu_category_id, :search_keyword, :min_price, :max_price))
end
And this is my view:
<%= simple_form_for :menuitem, :method => 'get', :url => {:action => 'index'} do |f| %>
<p>
<%= f.select :menu_category_id, options_for_select(#menucategories.map {|s| [s.title, s.id]}, params[:menu_category_id]), :selected => params[:menu_category_id], :onchange => "this.form.submit();", prompt: "Select category" %>
</p>
<p>
<%= f.input :search_keyword, input_html: { name: 'search_keyword', :value => params[:search_keyword]}, label: 'search recipe title', :required => false %>
<%= f.input :min_price, input_html: { name: 'min_price', :value => params[:min_price]}, label: 'min price:', :required => false %>
<%= f.input :max_price, input_html: { name: 'max_price', :value => params[:max_price]}, label: 'max price:', :required => false %>
<%= f.button :submit, "search" %>
</p>
<% end %>
You can save yourself the trouble of all the IF statements in your controller for all of the combinations by adding an IF statement within the scopes. For example, and this can similarly be applied to the four scopes associated to your form,
# menuitem model
scope :search_keyword, lambda { |query|
where(["name LIKE ?", "%#{query}%"]) if query != ""
}
This will allow to include only a single line in your controller, the line beneath your first IF statement, as this will handle the blank parameters.
There seems to be two issues with the category parameter. The first is it is a nested parameter within params[:menuitem], so in order to access it we need to call params[:menuitem][:menu_category_id]. Not too sure why this is happening to be honest, though I would recommend in this instance using a form_tag as opposed to form_for, given that we are not adding or editing the menuitems table itself.
The second issue is the category parameter is passed as a string, whereas we need it as an integer. We'll need to convert to parameter before applying it.
Now I'm not familiar with the .filters method (is this part of a gem?) but I got this to work the old fashioned way just by concatenating all the scopes together in one line as follows...
# menuitems controller
def index
#menuitems = Menuitem.newest_first.min_price(params[:min_price]).max_price(params[:max_price]).search_keyword(params[:search_keyword]).menu_category_id(params[:menuitem][:menu_category_id].to_i)
end
Note, another way of changing the data type would be to do so in the scope. You could do this as follows
# menuitem model
scope :menu_category_id, lambda { |menu_category_id|
where( "menu_category_id = ?", menu_category_id.to_i ) if menu_category_id != ""
}

Rails scopes with multiple arguments

In my offer.rb model I am doing some filtering after clients who have these offers.
But I want to be able to pass another param in my scope to search by, for example, the age of a client or so.
This is what I have now in my offer model:
scope :with_client_id, lambda { |client_id| where(:client_id => client_id) }
In the view:
<%= f.select(:with_client_id, options_for_select(current_partner.clients.collect{|c| [c.name, c.id]}), { include_blank: true}) %>
How can I pass a client's age per say in this scope?
Thanks!
Two Options
Using a "splat"
scope :with_client_id_and_age, lambda { |params| where(:client_id => params[0], :age => params[1]) }
And then you'd have to call it with:
Offer.with_client_id_and_age( client_id, age )
Using a params hash
scope :with_client_id_and_age, lambda { |params| where(:client_id => params[:client_id], :age => params[:age]) }
And then you'd have to call it with:
Offer.with_client_id_and_age( { client_id: client_id, age: age } )
I left the scope unchanged and just modified the select in the view:
<%= f.select(:with_client_id, options_for_select(current_partner.clients.collect{|c| [c.name_and_age, c.id]}), { include_blank: true}) %>
With the name_and_age method in the clients controller:
def name_and_age
[name, age].compact.join " "
end
I can type some age too in the select2 box to make the filterring.

calling a model function in the views in rails raising error

Here is the model
class Admin::Filter < ActiveRecord::Base
validates_uniqueness_of :name
has_many :filter_values,class_name: "Admin::FilterValue",foreign_key: "admin_filter_id"
enum field_type: [:select_tag,:select_tag_without_search,:check_box_tag]
def underscore_filter_name
if self.name.split.size > 1
self.name.replace(self.name.scan(/[A-Z][a-z]*/).join("_"))
else
"#{self.name.downcase}_filter"
end
end
end
The function I am talking about is underscore_filter_name. Now I am calling this inside the rails console like this: Admin::Filter.first.underscore_filter_name which returns a value but when I try similarly inside the view it throws an error. Here is the view:
-#filters.each do |filter|
%legend
=filter.name
-case filter.field_type
-when "select_tag"
= simple_form_for :"#{filter.underscore_field_name(filter)}",:url=> admin_requests_path,:method => "get",html: {:"data-filter"=>"#{filter.underscore_field_name}"} do |f|
= f.select("#{filter.name}", filter.filter_values.all.collect {|p| [ p.name, p.id ] }, {:include_blank => "Please select a #{filter.name}"},{:multiple => true,class: "form-control chosen-select select_tag_filter"})
-when "select_tag_without_search"
= select_tag "#{filter.name}", options_for_select(filter.filter_values.all.collect{ |u| [u.name, u.id]}), { :multiple => true,class: "search-free-chosen-select"}
-when "check_box_tag"
= simple_form_for :priority,:url=> admin_requests_path,:method => "get",html: {id: "priority_filter"} do |f|
= f.collection_check_boxes "#{filter.name}", filter.filter_values,:id,:name, :item_wrapper_class => 'inline'
The below line is the error I am getting:
undefined method `underscore_field_name' for #<Admin::Filter:0x007f07a322f068>
Why is this? I am using Rails 4.1
You have defined underscore_filter_name as the method name and you have typed in the view as underscore_field_name. So is the error.
Change it to
= simple_form_for :"#{filter.underscore_filter_name(filter)}",:url=> admin_requests_path,:method => "get",html: {:"data-filter"=>"#{filter.underscore_field_name}"} do |f|
This should resolve the error.
You've got in the view...
underscore_field_name
but the name of the method is
underscore_filter_name

Resources