Rails' Ransack Search with check_box for an associated model - ruby-on-rails

I got lost when I use 'ransack', a Rails Serching gem.
What I want to do is to work check-boxes for an asociated model.
Here is my code.
shows_controller.rb
class ShowsController < ApplicationController
def index
#q = Show.search(params[:q])
#shows = #q.result(:distinct => true)
#shows = #shows.joins(:tickets)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #shows }
end
end
index.html.erb
<%= search_form_for #q do |f| %>
<%= f.label "Show's Title: " %>
<%= f.search_field :title_cont %>
<%= f.label "Buy at:" %>
<%= check_box_tag 'q[shows_tickets_store_cont[]]', 'venue' %>At Venue
<%= check_box_tag 'q[shows_tickets_store_cont[]]', 'ticketmaster' %>Ticketmaster
<%= submit_tag "Find Now" %>
<% end %>
<% #shows.each do |show| %>
<%= show.title %> |
<% show.tickets.each do |ticket| %>
<%= ticket.store %><br />
<% end %>
<% end %>
show.rb
class Show < ActiveRecord::Base
has_many :tickets
end
ticket.rb
class Ticket < ActiveRecord::Base
belongs_to :show
end
When I wrote something in the search_field, checked the "check_box" and clicked "Find Now" button, the log showed like below;
Parameters: {"utf8"=>"✓", "q"=>{"title_cont"=>"something", "shows_tickets_store_cont"=>"venue"}, "commit"=>"Find Now"}
Show Load (1.1ms) SELECT DISTINCT `shows`.* FROM `shows` INNER JOIN `tickets` ON `tickets`.`show_id` = `shows`.`id` WHERE (`shows`.`title` LIKE '%something%') LIMIT 25 OFFSET 0
I have no idea why the SQL doesn't have WHERE clause for Ticket.store, in spite of ticket controller received "shows_tickets_title_cont"=>"venue".
Please, suggest solution for this.
Thanks in Advance.

Actually the problems is because your second key is: shows_tickets_store_con but is should be shows_tickets_store_cont. It accepts attribute if it has predicate _cont.
Ransack documentation:
https://github.com/ernie/ransack
cont (contains) and start (starts with) are just two of the available search predicates. See Constants for a full list.
# Edited 1
I made investigation a bit.
I do not think that your approach is good for your situation. If all the checkboxes are selected then you will have problems with your meta search - you have to set another predicate. In your situation it could be in predicate - because you use multiple values (checkboxes).
To have SQL like:
"shows_tickets_store" IN ('venue','something')
Possible predicates:
https://github.com/ernie/ransack/wiki/Basic-Searching
https://github.com/ernie/ransack/blob/master/lib/ransack/constants.rb
Also read this:
https://github.com/ernie/ransack/issues/20
https://github.com/ernie/ransack/issues/53

Related

doing an OR with ransack (rails)

I have these two inputs:
<%= search_form_for #search, url: search_path, method: :post do |f| %>
<%= f.text_field :thing_false %>
<%= f.text_field :thing_null %>
<% end %>
and when they're both set to "t", I get this query executed:
SQL: SELECT "stuffs".* FROM "stuffs" WHERE (("stuffs"."thing" = 'f' AND "stuffs"."thing" IS NULL))
How do I make it so I get this executed?
SQL: SELECT "stuffs".* FROM "stuffs" WHERE (("stuffs"."thing" = 'f' OR "stuffs"."thing" IS NULL))
The ransack documentation doesn't really address this. This is the closest example that I can find:
>> User.search(:first_name_or_last_name_cont => "Rya").result.to_sql
=> SELECT "users".* FROM "users" WHERE ("users"."first_name" LIKE '%Rya%'
OR "users"."last_name" LIKE '%Rya%')
If you don't want the user to have to select the "any" option, you can make it so that the search always uses "OR" by adding something like this in your controller:
#search = User.search(params[:q])
#search.combinator = "or"
#users = #search.result
You can also create different groupings of search fields and specify the appropriate combination within the grouping. The controller could have something like:
#search = User.search(params[:q])
(0..1).each do |index|
#search.build_grouping unless #search.groupings[index]
#search.groupings[index].combinator = "or"
end
#users = #search.result
And the view could have something like:
<%= search_form_for #search do |f| %>
<% #search.groupings.each.with_index do |grouping,index| %>
<%= f.grouping_fields grouping do |g| %>
<% if index == 0 %>
<%#= fields for first grouping here %>
<% end %>
<% if index == 1 %>
<%#= fields for second grouping here %>
<% end %>
<% end %>
<% end %>
<%= f.submit "Search" %>
<% end %>
The RansackDemo page is a good place to play around with the different search options. There is a Simple Mode and an Advanced Mode. The source code is available on github and the views there give some indication of how to put together the groupings and conditions.
Additional info is also available in RailsCast 370.
throw this under your search_form_for tag. This is assuming that you're using f:
<%= f.combinator_select %>
it'll generate a select with two options. ALL or ANY. ANY will use an OR clause. ALL will use an AND clause.

Rails filtering row by column using select dropdown

I was making a travel vacation application. Searching of places is based on categories from select dropdown.
But I am not able to understand the program logic. I am able to load the content in the database. but can't filter based on certain categories.
I made a scaffold called listing and included certain parameters.
In the database it has a row of 5 columns, namely, place, description, image_url, price, category.
Now, if I create another controller, search, I am not able to load a row based on a category from the select dropdown.
Search_controller.rb
def index
#categories = Listing.find_by_sql("SELECT category FROM listings GROUP BY category").map &:category
#list = params[:category].blank? ? Listing.all : Listing.find_all_by_category(params[:category])
end
index.html.erb
<% form_tag(:action => :index) do %>
<%= select_tag "category", options_for_select(#categories) %>
<%= submit_tag "Filter" %>
<% end %>
<table>
<% #list.each do |list| %>
<tr>
<td><%= list.place %></td>
</tr>
<% end %>
</table>
It does not show the select option.
Also, I tried to do this without select form
Search_controller.rb
def index
#list = Listing.select(:category).map(&:category).uniq
end
Index.html.erb
<% #list.each do |r| %>
<%= r.place %>
<% end %>
It says: undefined method `place' for "sunny":String (where "sunny" is a category)
Basically, how do you get the row based on a certain column value. And, will the logic also apply to two select dropdowns?
I know I am close, but somethings not right. Please assist me.
Thanks a lot.
You are missing = before form_tag. Should be:
<%= form_tag(:action => :index) do %>
<%= select_tag "category", options_for_select(#categories) %>
<%= submit_tag "Filter" %>
<% end %>

Rails Form element to convey two values

I have a form that takes bookings for an event for people. The form displays events vertically, and a name & checkbox for each of the possible people next to each event.
How should I best convey the two pieces of information that i need per checkbox? that is, the event_id and the person_id
I'm not totally sure wether I got you right. This is the model I assume you're talking about:
# event.rb
class Event
has_many :people
scope :possible_people, -> { #whatever .. }
end
# person.rb
class Person
belongs_to :event
end
# events_controller.rb
class EventsController
def index
#events = Event.all
end
end
And this might be a possible solution to change an events relation to people:
# index.html.erb
<ul id="events">
<% #events.each do |event| %>
<li class="event">
<%= form_for #event do |form| %>
<% event.possible_people.each do |person| %>
<%= check_box_tag "event[person_ids][]", person.id, #event.people.include?(person) %>
<% end %>
<%= f.submit_tag 'Save Event' %>
<% end %>
</li>
<% end %>
</ul>
The important part is <%= check_box_tag "event[person_ids][]", person.id, #event.people.include?(person) %> where you actually change the the relation of a specific person to the event.
Good luck ;)
Well, you can try out something like below line, I am assuming you have a multiselect checkboxes and i am passing a Hash of event_id => plate_id as value to checkbox.
<%= check_box_tag 'booking[event_people_ids][]', {booking.event_id => booking.plate_id} %>
You will get the value in params as:
booking => {event_people_ids =>["{"72"=>"3"}}
I ended up doing this:
<%= check_box_tag "booking[]", "#{event.id}-#{person.id}" %>
and then in then to process them:
params[:booking].each do |booking|
booking = booking.split('-')
a = {
:booking_id => #booking.id,
:person_id => booking[1],
:event_id => booking[0]
}
Appointment.create(a)
end
I was hoping for a more railish way to do it but this works.

checkboxtag in forms

Im looking for the following thing: an array of all users (only 6 in this case) with a checkbox in front of their name, resulting in a list of selectable players for the game.
Current code:
<%= form_for #game, url: games_path, :method => "post" do |f| %>
<%= f.label :name %>
<%= f.text_field :name, :value => "#{current_user.name}\'s Game" %>
<%= f.fields_for :participants do |ff| %>
<%= ff.label :user_id %>
<%= ff.text_field :user_id %>
<%= ff.check_box :user_id %>
<% end %>
<%= f.submit "Create Game", class: "btn btn-primary" %>
<% end %>
I'm now having 3.times { #game.participants.build } in my controller which effectively gives me 3 textfields in which i can fill in the participant id in order to make a record in the table participants (which is linked to games).
I've been looking around for 1.5h now and i cant seem to find a proper answer. What i need is a syntax that gives me a list of all current users (say #users) with a checkbox attached to it. When I click the checkbox it should add its id to the parameters and i should be able to create a new game with the linked participant id's. However I'm getting some problems with the ID's attached to the check_box which always seems to be 1. I've read some stuff about checkboxes being a pain with hashes, but I have no other solution atm.
I tried:
<% #users.each do |i| %>
<%= check_box_tag "alternate_numbers[#{i}]" %> <%= i.name %><br />
<% end %>
But i see no way to get that fixed up part of the form itself.
GamesController code (edit):
def new
#users = User.paginate(page: params[:page])
#games = current_user.games
#game = Game.new
3.times { #game.participants.build }
end
def create
#game = Game.new(params[:game])
#newround = #game.rounds.new
#newround.storyFragment = "New story!"
if #game.save && #newround.save
flash[:success] = "Created!"
redirect_to game_path(#game.id)
else
redirect_to root_url
end
end
It's very vague to describe since im not exactly sure how to accomplish this.
In short: the check_box should contain the value of the user_id in the loop. I'm now filling in a manual ID with the text_field helper but i'd like to have the checkbox linked to the username that is right next to it in the view.
Any guidelines/solutions/tips?
Thx
Okay, so you're making a form for a new Game. You now have to feed that new Game, along with some Participants to your view.
def new
#game = Game.new
#participants = User.all # or the users you want
end
Now use those in your view. You were on the right track. Depending on how your create action works:
<% #participants.each do |p| %>
<%= check_box_tag "participants[#{p.id}]" %> <%= p.name %>
<% end %>
I think what you were missing was the documentation for check_box_tag. The input attribute name is the argument.
You also seem to have a lot of logic in your controllers. Remember to keep the logic in the models, and only use the controllers to give the right objects to your views, and taking them for saving, for example. As the saying goes, "fat model, skinny controller".

How to get model objects in the form with rails check_box?

How do i get checkbox values in the form from the database? I want the form to bring the existing sub category name,and when i check the checkbox to select that particular category name and not create a new one.I have tried ryan bate's railscast but was no help to me. The realationship here is Category has_many SubCategories and SubCategory belongs_to Category.Thank you.
<%= form_for #category ,:url=>{:action =>"create"} do |f| %>
<%=f.text_field :category_name %>
<%= f.fields_for :sub_categories do |s| %>
<% #category.sub_categories.each do |sub|%>
<%=s.check_box "name",{},sub.id %> <!--need help here-->
<%end%>
<%end%>
<%=f.submit "submit"%>
<%end%>
Based on the exchange in the comments, it appears that you want to use the checkboxes to assign SubCategory objects to a Category object. If that's the case, you're association should be that a Category has_and_belongs_to_many :sub_categories. Then your form would look something like:
<%= form_for #category ,:url=>{:action =>"create"} do |f| %>
 <%=f.text_field :category_name %>
<% SubCategories.each do |sc| %>
<div>
<%= check_box_tag :sub_category_ids, sub_category_id, #category.sub_categories.include?(sc), :name => 'category[sub_category_ids][]' -%>
<%= label_tag :sub_category_ids, sc.name -%>
</div>
<% end -%>
<% end %>
Which will show a category form and then list all of the sub_categories that can be assigned or unassigned by checking the checkboxes.
You will also need a join table "categories_sub_categories" for this new association and logic (likely in your controller) to handle the actual assignment.
example for your category_controller.rb
def create
#category = Category.find(params[:id])
#use the checked sub_category_ids from the form to find and assign the sub_categories.
assigned_sub_categories = SubCategory.find(params[:category][:sub_category_ids]) rescue []
#category.sub_categories = assigned_sub_categories
if #category.save
…
else
…
end
end

Resources