Rails 4 select_tag with nested resource - ruby-on-rails

I have a resource that looks like this:
resources :teams do
[...]
get 'tags/:tag', to: "teams#show", as: :tag
end
Each Team can have multiple Posts which in it's turn can have multiple Tags. In my teams show view I want to display a select_tag that lists all the tags for the Team's Posts. When the user selects a tag I want to redirect them and list all posts for that tag. I have go it to work, but not with my nested resource and the URLs that I want. My implementation currently looks like this (I use HAML):
/ View
= form_tag team_path(#team), method: 'get', class: 'tag_form' do
.input-group
= select_tag "tag", options_from_collection_for_select(#team_tags, 'id', 'name', params[:tag]), prompt: "All tags", class: 'chosen-select'
# Controller
def show
#team_tags = #team.posts.tag_counts_on(:tags)
if params[:tag] && !params[:tag].blank?
tag = Tag.find(params[:tag])
#posts = #team.posts.tagged_with(tag.name)
else
#posts = #team.posts
end
end
This works, but gives me an url that looks like this:
teams/1?utf8=✓&tag=1
What I want is:
teams/1/tags/tag-name
Is that possible to do, and how would that look?

Based on this answer, you might be able to get this to work:
= select_tag "tag",
options_from_collection_for_select(#team_tags,
'id',
'name',
params[:tag]),
{prompt: "All tags",
class: 'chosen-select'},
{onchange: "window.location.replace('/teams/' + #team.id + '/tags/' + this.value);"}
the only thing i'm not sure about is if #team.id will interpolated correctly inside :onchange, so you could also try changing the onchange line to this:
onchange: "window.location.replace('/teams/#{#team.id}/tags/' + this.value);"

Try to use, or something like this (with your fields) on the controller
tag = Tag.where("id = ? OR name = ?", params[:tag], params[:tag])
And on the select you should use the name as value, maybe with a gsub like this
tag.name.gsub(" ", "-")

Related

Search through .select().group().distinct possible?

I want to create a search select that works on unique names through grouping...
The goal is to find duplicates to then use as a search parameter.
I want to find LineItem's :store_title's that match so I can create a select drop down for a way to search through LineItem's that match the specific :store_title.
Example:
LineItem DB:
line_item.title = "Hello"
line_item.title = "Hello"
line_item.title = "Okay"
line_item.title = "Bar"
I want to have a drop down select_tag in a search for the following:
[select]
"Hello"
"Okay"
"Bar"
And append all results that match LineItem.title of those which is selected.
I tried a few ways:
I so far have been able to get the unique drop down select field to "work" but not sure if it is the right way because it creates an array:
Controller:
#vendor_line_items = LineItem.where(vendor_id: #vendor.id).select(:store_title).group(:store_title).distinct
if params[:search]
#orders = Order.line_item_search(params[:search]).joins(:line_items).where(line_items: {vendor_id: #vendor.id})
end
ORders Model:
def self.line_item_search(search)
scope = joins(:line_items)
line_items = scope.where(line_items: { id: LineItem.where(store_title: "#{search.downcase}") })
line_items
end
View:
<%= form_tag vendor_orders_path, :method => 'get' do %>
<%= collection_select(:search, params[:search], #vendor_line_items, :store_title, :store_title, {}, {class: "form-control-sm col-5"})%>
<%= submit_tag "Search", :name => nil, class: "btn btn-primary btn-sm" %>
<% end %>
Error:
Undefined method 'downcase' for ["store_title"]:Array:
Can I alter my model to allow the array, or should i be finding the unique store titles another way?
If you just want to downcase the strings in that array, you could do something like this:
line_items = scope.where(line_items: { id: LineItem.where(store_title: search.map(&:downcase)) })
That will provide a list of downcased strings to your query.
I tried finding a way to remove the brackets before searching so the brackets were not present in the search parameters but couldn't figure it out.
Doing...:
line_items = scope.where(line_items: { id: LineItem.where(store_title: "#{search.join(', ')}") })
Solved it. This removes the brackets before searching the DB and works.
**
UPDATE:
**
View for response and answer to my issue:
Rails search form through arrays doesn't work on second search attempt

Search/ filter method for all attributes in my index table

I'm trying to write a row for my index table that filters my objects regarding a specific value of a specific column. What I have until now is this:
pimps_controller.rb:
def index
#pimps = Pimp.search(params[:search])
end
pimp.rb:
def self.search( search)
if search
where('title LIKE ?', "%#{search}%")
else
scoped
end
end
A part of view:
<%= text_field_tag :search, params[:search] %>
That filters after the objects title only so I tried to alter it to make it functional for different search fields that can filter after different attributes. I want to pass a second parameter value if someone fires the search function to make sure it triggers for the right attributes. That's what I've tried:
pimps_controller.rb
#pimps = Pimp.search(params[:search_column],params[:search])
pimp.rb:
def self.search(search_column, search)
if search
col = "%#{search_column}"
s = "%#{search}%"
where(col 'LIKE ?', s)
else
scoped
end
end
The view:
<%= text_field_tag :search, params[:search], params[:search_column => title] %>
But it's not working. I get an error message for passing the both parameters in one search field I guess. How would you do it?
Here's a simple tutorial on how to do it:
https://we.riseup.net/rails/simple-search-tutorial
In the model, you will have to add the fields with or condition to the query.
def self.search(search)
search_condition = "%" + search + "%"
find(:all, :conditions => ['title LIKE ? OR description LIKE ?', search_condition, search_condition])
end
If you want to define the field to search in the params you can use string interpolation with simple quotes:
%q(text contains "#{search.query}")
You need 2 text fields, one for the column, one for the value:
# view
<%= text_field_tag :search_value, params[:search_value] %>
<%= text_field_tag :search_column, params[:search_column] %>
# controller
#pimps = Pimp.search(params[:search_column], params[:search_value])
# Pimp model
def self.search(search_column, search_value)
if search_value.present? && search_column.present?
column = self.column_names.include?(search_column.to_s) ? search_column : 'title'
value = "%#{search_value}%"
where("#{self.table_name}.#{column} LIKE ?", value)
else
scoped
end
end
The problem about this method is that if you don't type the exact name of the column, it will search the value in the column title. I think you should use a select_tag, listing all searchable columns of the model:
# view
<%= select_tag :search_column, options_for_select(Pimp.column_names.map { |col| [col, col] }, params[:search_column]) %>
This view code will display a select tag with the available columns of the Pimp model. You can easily limit the searchable columns by defining a class method on Pimp:
# Pimp model
def searchable_columns
self.column_names - ['id', 'created_at', 'updated_at']
end
# view
<%= select_tag :search_column, options_for_select(Pimp.searchable_columns.map { |col| [col, col] }, params[:search_column]) %>

Simple rails filters

I have simplest rails app, with scaffold Tent
here my controller#index for
def index
#tents = Tent
#tents = #tents.where(:brand => params[:brand]) if params[:brand]
#tents = #tents.where(:season => params[:season]) if params[:season]
end
view also standart, generated by scaffold
and here search witch should filter data
= form_tag tents_path, method: :get do
= label_tag "manufacturer"
= select_tag :brand, options_for_select(...), include_blank: true
= label_tag "seasons"
- Tent.pluck(:season).each do |season|
=check_box_tag 'season', season
=h season
= submit_tag 'Submit'
Problem 1:
When i submit from, and params are unselected(select or checl_boxes) i don't want to send this params but they are sent with empty
GET /tents?utf8=...&brand=&season=&commit=Submit
Problem 2:
When i check multiple checkboxes get request is somthing like
GET /tents?utf8=...&brand=Brand&season=4&season=3&commit=Submit
after this i expect that data will be selected for both values, but controller expected that both values is in the field, and returns zero results
any suggestuions?
UPDATE
probably my question solved in railscasts-111 (advanced search form)
About problem 2:
You need to specify season checkbox like below:
=check_box_tag 'season[]', season
But i didnt test it
Problem 2:
You need to write javascript wrapper for form to serialize and send data on submit

Multiple identical collection_select tags in a form in Rails

I have multiple identical collection selects inside a single form. I prefer this over a multiple select list for aesthetic and UX reasons. I have to use a terrible kludge to make everything work right, and I'm wondering if there is a more elegant way to do this:
From the view:
<% 3.times do |i| %>
<%= collection_select("selected_item_" + i.to_s.to_s, :name, #items, :name, :name, { :include_blank => true }, { id: "selected_item_" + i.to_s }) %>
<% end %>
From the controller:
ItemContainer = Struct.new(:name)
3.times do |i|
param = ('selected_item_' + i.to_s).to_sym
instance_variable = '#' + param_name
if params[param] && !params[param].empty?
#selected_items << params[param][:name]
instance_variable_set(instance_variable, ItemContainer.new(params[param][:name]))
end
end
#selected_channels.each.... # do what I need to with these selections
Most of these gymnastics are needed to ensure that the item is still selected if the page is refreshed. If there were some way to force collection select to use arrays, that would be the answer, but I couldn't make that work.
If I understang right you're looking for selegt_tag method (docs: http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-select_tag)
You can write something like this
select_tag "people[]", options_from_collection_for_select(#people, "id", "name")
select_tag "people[]", options_from_collection_for_select(#people, "id", "name")
and it youd output two selects for people, which would be sent as an array on submit.
if you use the [] naming in your collection_select calls then the params will send over the data as an array
I am a bit confused as to the usage of collection_select here as it doesn't seem like you are using a model object? this example using select_tag - might be able to come up with something more appropriate to your issue if the model structures were known
# run this in the loop
# set selected_value to appropriate value if needed to pre-populate the form
<%= select_tag('name[]',
options_from_collection_for_select(#items, 'name', 'name', selected_value),
{ include_blank: true }
)
%>
in controller update/create action
# this works because the select tag 'name' is named with [] suffix
# but you have to ensure it is set to empty array if none are passed, usually only issue with checkboxes
names = params[:name] || []
names.each do |name|
puts name
end
side note: you can use string interpolation with ruby double quotes in places of + for string concatenation
<%= collection_select("selected_item_#{i}",
:name,
#items,
:name,
:name,
{ include_blank: true },
{ id: "selected_item_#{i}" }
)
%>
see also: http://apidock.com/rails/v3.2.13/ActionView/Helpers/FormOptionsHelper/options_from_collection_for_select

how to do two search in the same page with meta_search?

I have two list in a page, one for a model_1 and another for a model_2. When I click the sort_link of a column meta_search send the param "search[meta_sort]=column_name.asc". The problem is in the controller because the two models get filtered with the same search parameters:
#in the controller
#search_for_model_1 = Model1.search(params[:search])
#model_1s = #search_for_model_1.all
#search_for_model_2 = Model2.search(params[:search])
#model_2s = #search_for_model_2.all
#in the view
<%= sort_link #search_for_model_1, :name %>
<%= sort_link #search_for_model_2, :name %>
the sort_links are in different html tables, one showing model_1 fields and the another showing model_2 fields, when I click in any column name link, the param I get in the controller is params[:search], I have no way to know if the column link was clicked from model_1 or model_2 html table.
I want change the param name "search" for something like "search_for_model_name" then in the controller:
#in the controller
#search_for_model_1 = Model1.search(params[:search_for_model_1])
#model_1s = #search_for_model_1.all
#search_for_model_2 = Model2.search(params[:search_for_model_2])
#model_2s = #search_for_model_2.all
I could not find the way to change the param name using the helper method sort_link that meta_search provide. Or is there a different manner to do this?
sort_link uses the :as option just like form_for
<%= form_for #search, :as => :q do |f| %>
<%= sort_link #search, :field, :as => :q
#search = Model.metasearch(params[:q])
So do that with different names for each model.
most likely you just do something like this
:search_for_model_2 => :search_field
but I can't say for sure without seeing your view.
graywh's answer is not working for sort_link, this is the correct solution:
#in the controller
#search_for_model_1 = Model1.search(params[:model_1], :search_key => :model_1)
#search_for_model_2 = Model2.search(params[:model_2], :search_key => :model_2)

Resources