Custom searching a belongs_to assocation is empty - ruby-on-rails

sorry it may be simple but it's making me bash my head against a wall!
I created my own searches model and controller and having trouble searching a belongs_to association. I am able to search for has_and_belongs_to_many associations fine but I get zero results for belong_to.
# models/user.rb
class User < ApplicationRecord
belongs_to :city
has_and_belongs_to_many :sports
has_and_belongs_to_many :goals
end
# models/search.rb
class Search < ApplicationRecord
def search_users
users = User.all
# These two work
users = users.joins(:sports).where("sports.name ILIKE ?", "%#{sports}%") if sports.present?
users = users.joins(:goals).where("goals.name ILIKE ?", "%#{goals}%") if goals.present?
# This doesn't
users = users.joins(:city).where("cities.name ILIKE ?", "%#{cities}") if cities.present?
return users
end
end
# searches_controller.rb
class SearchesController < ApplicationController
def new
#search = Search.new
#sports = Sport.uniq.pluck(:name)
#goals = Goal.uniq.pluck(:name)
#cities = City.uniq.pluck(:name)
end
def create
#search = Search.create(search_params)
redirect_to #search
end
def show
#search = Search.find(params[:id])
end
private
def search_params
params.require(:search).permit(:sports, :goals, :gyms, :cities)
end
end
and my views:
#searches/new.html.erb
<%= simple_form_for #search do |search| %>
<%= search.label :sports %>
<%= search.select :sports, options_for_select(#sports), include_blank: :true %>
<%= search.label :goals %>
<%= search.select :goals, options_for_select(#goals), include_blank: :true %>
<%= search.input :cities, collection: City.all.order(name: :asc), as: :select, label: "City" %>
<%= submit_tag "Search" %>
<% end %>
searches/show.html.erb
<% if #search.search_users.empty? %>
Nothing
<% else %>
<% #search.search_users.each do |user| %>
<%= user.first_name + ' ' + user.last_name %>
<% end %>
<% end %>
Basically when selecting a City from the dropdown list it doesn't register and gives me the empty search condition and I can't figure out why it won't select it. However selecting the sports and/or goals and it gives me the user matching those.
Thanks in advance!
EDIT:
Okay I've managed to get it working by simply changing my dropdown select in my view from:
<%= search.input :cities, collection: City.all.order(name: :asc), as: :select, label: "City" %>
to this:
<%= search.select :cities, options_for_select(#cities) %>
HOWEVER, I'd still like to know why the other way doesn't work?

<%= search.input :cities, collection: City.all.order(name: :asc), as: :select, label: "City" %>
One of the reasons the above code didn't work is,
City.all.order(name: :asc) return a ActiveRecord::Relation object, but a collection searches for an array or range.
Collections can be arrays or ranges. from the collection documentation
Another point from that documentaion is,
when a :collection is given the :select input will be rendered by default, so we don't need to pass the as: :select
So, change the input to
<%= search.input :cities, collection: City.uniq.pluck(:name).sort,label: "City" %>

Related

How to make columns from joined tables available in Ransack attribute field?

I want to display belongs_to relationship columns in ransackable attributes list. So that I can display them in the dropdown, and perform an advanced search on the (joined) table.
How can I do that?
Below my model, where each manifest has one consignee. I've adjusted the attribute list, but when I select the consignee name it looks for 'manifest'.'name' and not in 'consignee'.'name' via a JOIN.
When I use the simple search form, it works correctly.
manifest.rb
class Manifest < ApplicationRecord
belongs_to :shipper
belongs_to :consignee
...
def self.ransackable_attributes(auth_object = nil)
super - ['id', 'created_at', 'updated_at', 'consignee_id']
super + ['consignee_name']
end
end
consignee.rb
class Consignee < ApplicationRecord
has_many :manifest, dependent: :destroy
...
end
manifest_controller.rb
...
def index
#search = ransack_params
#search.build_grouping unless #search.groupings.any?
#manifests = #search.result(distinct: true)
#search.build_condition
...
private
def ransack_params
Manifest.includes(:vessel, :pod, :pol, :por, :del, :consignee).ransack(params[:q])
end
end
index.html.erb
<%= search_form_for #search do |f| %>
<%= f.condition_fields do |c| %>
<div class="field">
<%= c.attribute_fields do |a| %>
<%= a.attribute_select %>
<% end %>
<%= c.predicate_select :only => [:cont, :not_cont, :matches]%>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
</div>
<% end %>
I expect to see Consignee Name in the dropdown list, but only see 'Name' at the bottom. When I select this and press search it returns with an error:
undefined method `type' for nil:NilClass
on line: Manifest.includes(:vessel, :pod, :pol, :por, :del, :consignee).ransack(params[:q])
manifest.rb (define ransackable_attributes only for this model)
class Manifest < ApplicationRecord
belongs_to :shipper
belongs_to :consignee
...
private
def self.ransackable_attributes(auth_object = nil)
super - ['id', 'created_at', 'updated_at', 'consignee_id']
end
end
consignee.rb (define ransackable_attributes for this model)
class Consignee < ApplicationRecord
has_many :manifest, dependent: :destroy
...
private
def self.ransackable_attributes(auth_object = nil)
if auth_object == :manifest_search
['name']
else
super
end
end
end
manifest_controller.rb
...
def index
#search = ransack_params
#search.build_grouping unless #search.groupings.any?
#manifests = #search.result(distinct: true)
#search.build_condition
...
private
def ransack_params
Manifest.ransack(params[:q], auth_object: :manifest_search)
end
index.html.erb (add the associations parameter to attribute_select)
<%= search_form_for #search do |f| %>
<%= f.condition_fields do |c| %>
<div class="field">
<%= c.attribute_fields do |a| %>
<%= a.attribute_select :associations => ["consignee"] %>
<% end %>
<%= c.predicate_select :only => [:cont, :not_cont, :matches]%>
<%= c.value_fields do |v| %>
<%= v.text_field :value %>
<% end %>
</div>
<% end %>
note that the auth_object conditional is optional, but it allows you to have different search pages with different attributes. For example, the consignee page could have its own search form showing all of consignee's attributes, while the manifest search shows only the consignee name as a searchable attribute.
I removed the includes to simplify the code; it's not required to make the search work. If you need those associations pre-loaded, you can put it back in.

Rails polymorphic association won't save _type

I have a few models in my project : Request, Work, Car and Employee. Work is an intermediate model between Request and Car/Employee.
Here are the associations:
Request
has_many :works, dependent: :destroy
def performers
works.map {|x| x.performer}
end
Work
belongs_to :request
belongs_to :performer, polymorphic: true
Car
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
Employee
has_many :works, as: :performer
has_many :requests, through: :works, as: :performer
View used to create works:
<%= form_for([#request, #work]) do |f| %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) if #request.type == "StaffRequest" %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) if #request.type == "CarRequest" %>
<%= f.submit 'OK' %>
<% end %>
Work controller
def new
#work = #request.works.new
end
def create
#work = #request.works.new(work_params)
end
def work_params
params.require(:work).permit(:performer_id, :request_id)
end
The problem is that my performer_type column is always empty, it does not save the class name. What can be the problem? Any ideas?
It's empty because you did't pass it, you should add a hidden field for you form:
<%= form_for([#request, #work]) do |f| %>
<% if #request.type == "StaffRequest" %>
<%= (f.hidden_field :performer_type, value: "Employee") %>
<%= (f.collection_select :performer_id, Employee.all, :id, :name) %>
<% elsif #request.type == "CarRequest" %>
<%= (f.hidden_field :performer_type, value: "Car") %>
<%= (f.collection_select :performer_id, Car.all, :id, :select_info) %>
<% end %>
<%= f.submit 'OK' %>
<% end %>
Beside :performer_id, you have to pass the :performer_type also, one way to do this is via the form select_tag :
def create
#work = #request.works.new(work_params)
end
def work_params
# use :performer if you use :performer as in the select form field
params.require(:work).permit(:performer, :request_id)
# OR
# use :performer_id & :performer_type if you also use the hidden field
params.require(:work).permit(:performer_id, :performer_type, :request_id)
end
There is a good example (for Rails 4.2) of using a single select form field for polymorphic so you can write like:
<%= f.grouped_collection_select :global_performer, [ Car, Employee ], :all, :model_name, :to_global_id, :name %>
How to create grouped select box in Rails for polymorphic association using Global ID?

How can I rectify ActiveRecord::Associations::CollectionProxy

I am creating a category select dropdown to add categories to an event.
I can add them and they are showing in the form for the edit area, I can see the categories added in the backend.
When I try to show them in the views it gives me this strange error inside the layout:
<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Category:0x00000102542f10>
In my setup I have got this:
views/events/index.html.erb
<%=
event.categories.each do |events|
category.name
end
%>
models/category.rb
class Category < ActiveRecord::Base
belongs_to :event
belongs_to :profile
belongs_to :classified
belongs_to :page
extend FriendlyId
friendly_id :name, use: :slugged
end
admin/category.rb
ActiveAdmin.register Category do
controller do
def permitted_params
params.permit category: [:name, :description]
end
def find_resource
scoped_collection.friendly.find(params[:id])
end
end
form do |f|
f.inputs "Name" do
f.input :name
end
f.inputs "Description" do
f.input :description, :as => :ckeditor, :label => false, :input_html => { :ckeditor => { :toolbar => 'Full', :height => 400 } }
end
f.actions
end
end
In my categories table there is an event_id column in there so it can fnd the associated event and it links to both the events table and the categories table.
Any insight into this would be great
Thanks
Update views/events/index.html.erb as below:
<% if event.categories.count > 0 %>
<% event.categories.each do |category| %> ## Use <% %> to evaluate ruby code
<%= category.name %> ## Use <%= %> To evaluate and show the results
<% end %>
<% end %>
In your case, <%= %> will return event.categories value which is an instance of <ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_Category which is what you see on the rendered page.
UPDATE
OP also had foreign_key concerns. Add foreign_keys for event, profile, classified and page in categories table.

How can i update my lisbox using ajax?

How can i create an ajax in my search when i select a country it would show me all states that i have in the country selected
I'm trying to create a display when i select country automatically show all the states that has the country selected
My tables
Countries
|id| |country_name|
1 'USA'
2 'Peru'
States
|id| |state_name|
1 Alabama
2 Machupicchu
Country_States
|id| |country_id| |state_id|
1 1 1
2 2 2
My controller
class Country_StatesController < ApplicationController
def conditional
#countries = Country.find(:all)
#states= State.find(:all)
#selected_country = Country.find_by_id(params[:countries]) if params[:countries].to_i
#selected_state = State.find_by_id(params[:states]) if params[:states].to_i
#search= CountryState.find(:all,:conditions=> ['state_id','country_id' ],params[:states],params[:countries] )
end
end
My view
<% form_tag :controller=>"country_States",:action=>"conditional" do %>
<%= select_tag "countries", options_for_select(#countries.collect {|t| [t.state_name.to_s ,t.id]}) %>
<%= select_tag "states", options_for_select(#states.collect {|t| [t.state_name.to_s ,t.id]}, params[:search].to_i ) %>
<%= submit_tag "Search", :name => nil %>
<% end %>
I found something like this
<%= collection_select :selection, :level, User::LEVELS, :to_s, :to_s, {},
{:onchange => remote_function(
:url => {:action => "updatelevel", :controller => "user", :id=> user.id},
:with => "'level_id='+this.value"
)
}
%>
I will appreciate help.
To list all the states belonging to a given country first set up the following relationship:
class Country < ActiveRecord::Base
has_many :states
end
class State < ActiveRecord::Base
belongs_to :country
end
Then in the controller you can call all states like this:
#country = Country.find(params[:id])
#states = #country.states #this will be a hash of all states that belong_to #country
and in the view, you can create a list like this (or use a table, depending on how you want it to be formatted):
<ul>
<% #states.each do |state| %>
<li>
<%= state.name %>
</li>
#etc
<% end %>
</ul>
I found a very simple answer here:
http://pullmonkey.com/2008/03/30/dynamic-select-boxes-ruby-on-rails/
Is very useful and descriptive.

Passing Checkbox values to model

I am making a model where users can belong to multiple teams and teams have multiple people.
I have checkboxes but they don't pass the value onto the object.
class User < ActiveRecord::Base
attr_accessible :email, :name
has_many :teams
accepts_nested_attributes_for :teams
end
class Team < ActiveRecord::Base
has_many :users
attr_accessible :name
end
Here is the code in my controller
def create
#users = User.all
#user = User.new
#teams = Team.all
#user.attributes = {:teams => []}.merge(params[:user] || {})
end
Here is the code in my view file
<%= form_for #user, url: {action: "create"} do |f| %>
<%= f.label :teams%>
<% for team in #teams %>
<%= check_box_tag team.name, team.name, false, :teams => team.name%>
<%= team.name -%>
<% end %>
<%= submit_tag "Create User" %>
I am trying to show it into
<%= user.teams.name %>
But the only output is "Team"
Can someone tell me what I am doing wrong?
Actually, you can't do a many-to-many relationship that way... you need to do has_many :through or alternatively has_and_belongs_to_many Nice explanation here...
http://guides.rubyonrails.org/association_basics.html

Resources