Filtering an Index - ruby-on-rails

I have the following index method
def index
#user = User.find_by_username(params[:user_id])
#search = #user.collections.where(status: params[:status]).search(params[:q])
#search.sorts = 'created_at desc' if #search.sorts.empty?
#collections = #search.result.paginate(page: params[:page])
end
I can then use the following links to display different indexes with that one action
<%= link_to "Collection", user_collections_path(current_user, :status => "Got") %>
<%= link_to "Wantlist", user_collections_path(current_user, :status => "Want") %>
But I want to also be able to link things like this, using other fields to filter the index
<%= link_to "Assembled", user_collections_path(current_user, :progress => "Assembled") %>
and I can't see how to write that. Should I be using scopes or should I have alternative methods in my controller? Is my initial "where" filter a bad way of doing this in the first place?

The best way I found to do this is with the has_scope gem.
Installed that. Named scopes in my model as follows
scope :assembled, -> { where(progress: 'Assembled') }
scope :got, -> { where(status: 'Got') }
scope :want, -> { where(status: 'Want') }
Added the has_scope fields to the controller
has_scope :got, :type => :boolean
has_scope :want, :type => :boolean
has_scope :assembled, :type => :boolean
Then my index method as follows
def index
#user = User.find_by_username(params[:user_id])
#search = apply_scopes(#user.collections).search(params[:q])
#search.sorts = 'created_at desc' if #search.sorts.empty?
#collections = #search.result.paginate(page: params[:page])
end
Then I can link to the index with any combination of those scopes like this
<%= link_to collection, user_collections_path(#user, got: true) %>
<%= link_to assembled, user_collections_path(#user, got: true, assembled: true) %>
No routes and no extra methods. Very clean and expandable.

Use a Gem instead
This is a solved problem. I would use a gem like ransack to do this rather than re-inventing the wheel. It has great helper methods to provide any kind of filtering that you would need.

Routes
Further to San's answer, you'll need to create routes to handle any data you wish to send to your index (for filtering):
You'd do something like this:
#config/routes.rb
resources :users, except: :show do
collection do
get "(:query)", action: :index #-> domain.com/users/:query
end
end
This will allow you to create links like this:
<%= link_to "Link", users_path(current_user, query: "whatever") %>
--
Controller
Inside your controller, all the links will hit your index action, so you'll just need some conditions to make sure you can handle a "non search" request:
def index
#user = User.find_by_username(params[:user_id])
if params[:status].present? && params[:q].present?
#search = #user.collections.where(status: params[:status]).search(params[:q])
#search.sorts = 'created_at desc' if #search.sorts.empty?
#collections = #search.result.paginate(page: params[:page])
end
end

Related

Rails Call A Method Lastly In Action

I have something like that in my controller:
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
I want to use search method in index action but I don't want to remove my #votes variable from index. If I use before_action, it calls method before the action so #votes doesn't change. Is it possible to call search method after my votes variable or ignore the variable without removing.
I normally go with this method when I'm looking to build a simple search:
http://railscasts.com/episodes/37-simple-search-form
Create a method in your vote.rb file:
class Vote
def self.search(search)
if search
self.where(:all, conditions: ['name LIKE ?', "%#{search}%"])
else
self.where(:all)
end
end
end
This means when you do Vote.search('term'), you'll bring up any records with a similair name. Replace name for whatever term you're searching for (i.e. title or category).
If there is no search term entered this method simply returns every instance. This means you can leave your controller looking like this:
def index
#votes = Vote.search(params[:search])
end
Finally the view for this would be something like:
<% form_tag votes_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
This will send a get request to the votes_path (the index action on your controller), with the search term parameter. If one is entered the search will return the relevant instances, and if not it will return all.
Try
class TempController < ApplicationController
after_action :search
def index
#votes = Vote.all
end
private
def search
#votes = OtherVotes.all
end
end

rails 3 search between multiple models

I want to avoid some gems so I came up with this solution to search between multiple models.
But It seem to just work for first model that is listed.
SearchController :
def index
#products = Product.search(params[:search]).paginate(:per_page => 5, :page => params[:page])
#manufacturer_name = Manufacturer.search(params[:search]).paginate(:per_page => 5, :page => params[:page])
#category_name = Category.search(params[:search]).paginate(:per_page => 5, :page => params[:page])
end
Inside my 3 models I have like this:
def self.search(search)
if search
where('name LIKE ? ', "%#{search}%")
else
scoped
end
Search#index
<%if #products.present?%>
<%= render partial: "products/found" %>
<%end%>
<%if #manufacturer_name.present?%>
<%= render partial: "products/foundmanufacturers" %>
<%end%>
<%if #category_name.present?%>
<%= render partial: "products/foundmanufacturers" %>
<%end%>
I prepared for each model seperated partial.
But when I search for name that definetely should be in all categories. But there is no results found, only when I run search for products name. Then I get results I want.
Any tip would be great. Tnx
it's just refactoring create name scope like as shown below
scope :by_name,lambda{|name| where("name like (?)","%#{name}%") if name.present?}
# In controller
Product.by_name(params[:search]).paginate(:per_page => 5, :page => params[:page])
no need of search method in model it's better to write scope unless you are doing some complex checking,
Second try to see in console wether you are getting results based on your search params?

undefined method `page' for #<Array:0xbc0ff98>

My Active admin version is 0.3.0, other than that m also using 'Will_paginate' i had made the configuration settings of conflict between kaminari and will_paginate but still m getting this error. i dont know where m making a mistake everything is working fine for other model but not for this model, need help, i have searched also found some links but not get satisfactory answer, it give me error on bold line
ActiveAdmin.register User do
menu :parent => 'Reports'
filter :id
filter :user_id
filter :updated_at
# and other filters
scope :all, :default => true do |user|
User.all
end
scope :active do |user|
User.where("user.status = ?", 'actvie')
end
scope :rejected do |user|
User.where("user.status = ?", 'non_active')
end
actions :index, :show
index do
column "ID" do |u|
link_to u.id, cs_user_path(u)
end
column "Status" do |u|
status_tag(u.status)
end
column "User" do |u|
link_to(u.user.full_name, cs_user_path(u.user)) rescue nil
end
end
collection_action :index, :method => :get do
scope = User.includes([:group,:address]).scoped
scope = scope.order params[:order].gsub(/_/,' ') if params[:order]
#collection = scope.paginate(:per_page => 25,:page => params[:page]) if params[:q].blank?
#search = scope.metasearch(clean_search_params(params[:q]))
**super do |format|**
format.html {
render "active_admin/resource/index"
}
end
end
end
The GitHub documentation of will_paginate states that arrays are not supported that well.
I will suggest using the kaminari gem which includes a helper method for array pagination.
You should be able to take it from here.

Simple search on a Globalize3 table in Rails

I am looking to implement a simple search function while using the globalize3 gem for Ruby on Rails. Since the translations of the model are stored in a separate table, the code below doesn't work as there is no longer a :name field in the products table. How can I adjust the code below to make the search function correctly?
products_controller.rb
#products = Product.search(params[:search]).all
index.html.erb
<%= form_tag products_path, method: :get do %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", name: nil %>
<% end %>
model
class Product < ActiveRecord::Base
translates :name
attr_accessible :name, :price, :released_at
def self.search(search)
if search
where('name LIKE ?', "%#{search}%")
else
scoped
end
end
end
You're in luck, I tackled exactly the same problem recently!
Luckly for you the answer is quite simple. You can use the class method with_translations to include translations for a given set of locales.
Here's the code:
def with_translations(*locales)
locales = translated_locales if locales.empty?
includes(:translations).with_locales(locales).with_required_attributes
end
Include it in your search method:
def self.search(search)
if search
with_translations.where('name LIKE ?', "%#{search}%")
else
with_translations
end
end
That should do it.
As an added note: you could add an optional locales parameter to the search method and pass it to with_translations to optionally narrow the search to terms in a particular language, say for example in the current locale.
Solved ...
def index
if params[:search]
#at = []
#at = Array.new
Article.translation_class.where("title LIKE ? OR description LIKE ?","%#{params[:search]}%","%#{params[:search]}%").all.each do |t|
#at.push t.article_id
end
#articles = Article.where(id: #at).recent_first.paginate(page: params[:page], per_page: 5)
else
#articles = Article.all.recent_first.paginate(page: params[:page], per_page: 5)
end
end

How to implement simple search form to be used in conjunction with paginate?

I am following Ryan Bates' railcasts: http://railscasts.com/episodes/37-simple-search-form
in solving my issue with the search results on a page with will-paginate.
Here he answers the question as to how to solve this problem. However, I've tried them and haven't had any luck. From following his second resolution, I get a NoMethod error for "search_conditions" as the result.
The Code:
projects/index.rhtml
<% form_tag projects_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
projects_controller.rb
def index
#projects = Project.search(params[:search])
end
models/project.rb
def self.search(search)
if search
find(:all, :conditions => ['name LIKE ?', "%#{search}%"])
else
find(:all)
end
end
His Answers:
One way is to call the class method "search_conditions" and instead of having it do the find it will just return a conditions array so you could use it in the paginate method.
Course.paginate(:all, :conditions => Course.search_conditions(..))
Another is to call the method "paginated_search" and have it call "paginate" instead of "find".
Lastly you could have the search method accept a block which uses with_scope to set the find conditions. This way you could call "paginate" in that block and the conditions will automatically be applied.
Can someone explain to me how I should go about solving this? I am new to rails and maybe I am just misunderstanding what he is saying.
Railscast you following is pretty old, lots changed since then. Try to change implementation of search method like this:
def self.search(search)
if search
where 'name LIKE ?', "%#{search}%"
else
scoped
end
end
and something like this in controller:
def index
#projects = Project.search(params[:search]).paginate(:page => params[:page])
end

Resources