Can't sort table in rails - ruby-on-rails

I'm having trouble sorting a single-column table in Rails. Each row represents a single object (an article) and contains all of its attributes (name, content, created_at, user, etc.). The search function works fine (Article.where) but I can't seem to sort the table by any attributes, i.e. Article.order('attribute'). The default, which I can't change, is created_at desc. Am I overlooking something?
Here is my controller:
def index
#title="Home"
if params[:search]
#search=params[:search]
#articles=Article.where('name LIKE ? OR category LIKE ?', "%#{params[:search]}%", "%#{params[:search]}%").paginate(:per_page => 15, :page => params[:page])
else
#articles=Article.order('name').paginate(:per_page => 15, :page => params[:page])
end
end
And view:
<table>
<%= render #articles%>
</table>
<%= will_paginate #articles, :previous_label => "Prev", :next_label => "Next" %>

Use reorder to override any default ordering.
Article.reorder('name').paginate(:per_page => 15, :page => params[:page])

I recommend my gem simple-search for these problems. It may be too simple, but worth a shot.

Related

Ruby on Rails: Show default result before using dropdown filter with will_paginate

I can display the results by 10, 15, or 20 by using a drop-down. The issue is when the app loads it displays all results. I would like to display only 10 results by default before using the drop-down filter to display more results.
Can someone help please?
Thank you!
This is my VIEW:
<%= select_tag :per_page, options_for_select([10,15,20], #per_page), :onchange => "if(this.value){window.location='?per_page='+this.value;}" %>
This is my CONTROLLER:
#per_page = params[:per_page] || Post.per_page
#posts= Post.all.paginate(:per_page => #per_page, :page => params[:page])
Try this code:
#per_page = params[:per_page] || Post.per_page
#posts= Post.paginate(per_page: #per_page, page: params[:page])
Note that I call paginate without on Post class itself and not on result of Post.all.
I also removed the last || 10 part. I think you don't need it there as you already set this value on Post model.

Sunspot Solr fulltext search and will_paginate

The following query is working like a charm:
#styles = Style.search { fulltext params[:q] }
The problem I'm having is with pagination. Here is the same query with pagination:
#styles = Style.search { fulltext params[:q]; paginate :page => params[:page], :per_page => params[:page_limit] }
I have 11 Style records.
If I have :page => 1 and :per_page => 10 when I search for the 11th record, I get an empty array returned for #styles.results
If I set :page=>2 and do the same search I get the 11th style record.
[11] pry(#<StylesController>)> params[:page]=2
=> 2
[12] pry(#<StylesController>)> x=Style.search {fulltext params[:q]; paginate :page => params[:page], :per_page => params[:page_limit] }
=> <Sunspot::Search:{:fq=>["type:Style"], :q=>"hel", :fl=>"* score", :qf=>"name_textp full_name_textp", :defType=>"dismax", :start=>10, :rows=>10}>
[13] pry(#<StylesController>)> x.results
=> [#<Style id: 15...>]
I thought the point was to paginate the search results, not the actual records in their entirety
What's going on here, and how do I fix it?
EDIT
Ok, let me try explaining this another way. Let's say I have these six records:
1 => 'a'
2 => 'b'
3 => 'c'
4 => 'd'
5 => 'e'
6 => 'f'
Let's say I try to search for 'f'
Letter.search { fulltext 'f'; paginate :page => 1, :per_page => 5 }
My result will be an empty array []
Now let's say I try
Letter.search { fulltext 'f'; paginate :page => 1, :per_page => 6 }
Now my result is [6 => 'f']
my thoughts:
get the results from solr then search your model by ids that solr returned and paginate them, something like this:
#search = Sunspot.search(Snippet) do
fulltext params[:search]
end
#styles = Style.where(id: #search.results.map(&:id)).page(params[:page]).per(5)
what I understood from docs: I didn't tried it
By default, Sunspot requests the first 30 results from Solr. That means you can have 100 of records that might match the searching criteria but you'll see only the first 30, to see the others you have to add the paginate to your solr search, like:
search = Style.search do
fulltext "my cool style"
paginate :page => 2
end
in this case, you should be able to access 2 page. To update the number of sunspot requests you need to write:
search = Style.search do
fulltext "my cool style"
paginate :page => 1, :per_page => 50
end
it should give you 50 results in one page, or paginate :page => 2, :per_page => 50 and results should be divided in 2 pages with max 50 results each.
Try supply a fallback to per_page like so:
#search = Style.search do
fulltext params[:q]
paginate(page: params[:page], per_page: (params[:per] || 15))
end
I also faced the same problem. So I removed :per_page tag in my search
And changed my query as
#styles = Style.search { fulltext params[:q]; paginate :page => params[:page]}
To set the per_page_limit, I used the following code in my initializers
Sunspot.config.pagination.default_per_page = 20
You can use the "hits" method.
In the controller
#search = User.search do
with :name, 'joe'
end
In the view
<% #search.results.each do |result| %>
<%= result.name %>
<% end %>
<%= will_paginate #search.hits unless #search.nil? %>

Rails: Sorting and Filting Data based on boolean attribute

I have a basic model of "Projects", which currently only has the attributes name:string, active:boolean. On the index view, I want to be able to have three links: Active Projects, Inactive Projects, and All Projects. These links will display the appropriate projects based on the status of the :active boolean value. Initially I set up the view by giving the links params like:
link_to "Active Projects", {:action => 'index', :active => true}
Then in the controller:
if params[:active] == "true"
#projects = Project.find(:all, :conditions => {:active => true})
elsif params[:active] == "false"
#projects = Project.find(:all, :conditions => {:active => false})
else
#projects = Project.all
This seems a little cumbersome, especially since in future I want to have multiple filters, like due date, and client. What is a good way / gem to implement advanced sorting / filtering actions, without filling up the controller with a lot of code?
You could structure your params as a hash, and pass it to conditions:
# example:
params = {
:filters => {
:active => true,
:name => 'Boby',
# etc...
}
}
filters = params[:filters]
#projects = Project.where(filters)
I would recommend using where statements.. Also here is your code refactored :
#projects = Project.all
#projects = #projects.where(active: params[:active]) if params[:active].present?
Then you can keep stacking on items if additional params exist like so :
#projects = #projects.where(awesome_sauce: params[:awesome_sauce]) if params[:awesome_sauce].present?

How to I make a drop down beside a search box that searches the specific field selected in rails?

Okay so im new to this site but this is what I have:
Report.rb
def self.search(search)
if search
where('JOBLETTER_CD_NUMBER LIKE ? AND DATE LIKE? AND CUST LIKE ?', "%#{search}%")
else
scoped
end
end
end
index.html.erb
select_tag "search", options_for_select([ "Job Letter and CD #", "Date", "Cust", "Job", "Date shipped", "Date billed", "Billed by" ], params[:search])
form_tag reports_path, :method => 'get' do
text_field_tag :search, params[:search], :class=> "form-search", :align => "right"
<%= submit_tag "Search", :JOBLETTER_CD_NUMBER => nil, :class => "btn btn-success", :align => "right"
reports controller
def index
#report = Report.paginate(:per_page => 1, :page => params[:page])
#report = Report.search(params[:search]).paginate(:per_page => 1, :page => params[:page])
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #views }
end
end
The only field it will search is the Job Letter and CD # field I need it to allow me to search whatever is selected in the drop down box. Btw I am using bootstrap fro js and css functions.
Your query has 3 placeholders ? but passed only one argument "#{search}" - if you run it like that, what you really should be getting is an exceptions stating
ActiveRecord::PreparedStatementInvalid: wrong number of bind variables (1 for 3) ...
Also, your select_tag is outside the form, so it won't be passed to the controller at all. If you move it into the form, you'd have to rename (e.g. to column) it since the name search is already used by the text field. Then you could pass both the column and the search parameters to your search function to construct the query.
HOWEVER, this is not safe, since nothing prevents a user to pass in any other column by manipulating the post request, and since you can't use placeholders for column names, there's a danger of SQL injection as well.
There are many solutions out there to construct searches, no need to reinvent the wheel. Take a look at the ransack gem. Here's a recent Railscast on how to use it.

Searching in Ruby on Rails - How do I search on each word entered and not the exact string?

I have built a blog application w/ ruby on rails and I am trying to implement a search feature. The blog application allows for users to tag posts. The tags are created in their own table and belong_to :post. When a tag is created, so is a record in the tag table where the name of the tag is tag_name and associated by post_id. Tags are strings.
I am trying to allow a user to search for any word tag_name in any order. Here is what I mean. Lets say a particular post has a tag that is 'ruby code controller'. In my current search feature, that tag will be found if the user searches for 'ruby', 'ruby code', or 'ruby code controller'. It will not be found if the user types in 'ruby controller'.
Essentially what I am saying is that I would like each word entered in the search to be searched for, not necessarily the 'string' that is entered into the search.
I have been experimenting with providing multiple textfields to allow the user to type in multiple words, and also have been playing around with the code below, but can't seem to accomplish the above. I am new to ruby and rails so sorry if this is an obvious question and prior to installing a gem or plugin I thought I would check to see if there was a simple fix. Here is my code:
View: /views/tags/index.html.erb
<% form_tag tags_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search], :class => "textfield-search" %>
<%= submit_tag "Search", :name => nil, :class => "search-button" %>
</p>
<% end %>
TagsController
def index
#tags = Tag.search(params[:search]).paginate :page => params[:page], :per_page => 5
#tagsearch = Tag.search(params[:search])
#tag_counts = Tag.count(:group => :tag_name,
:order => 'count_all DESC', :limit => 100)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #tags }
end
end
Tag Model
class Tag < ActiveRecord::Base
belongs_to :post
validates_length_of :tag_name, :maximum=>42
validates_presence_of :tag_name
def self.search(search)
if search
find(:all, :order => "created_at DESC", :conditions => ['tag_name LIKE ?', "%#{search}%"])
else
find(:all, :order => "created_at DESC")
end
end
end
If I read your problem correctly, you want to return a row if the tag names for the row matches one of the words passed in the query string.
You can rewrite your search method as follows:
def self.search(search)
all :conditions => (search ? { :tag_name => search.split} : [])
end
If you need partial matching then do the following:
def self.search(str)
return [] if str.blank?
cond_text = str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
cond_values = str.split.map{|w| "%#{w}%"}
all(:conditions => (str ? [cond_text, *cond_values] : []))
end
Edit 1
If you want pass multiple search strings then:
def self.search(*args)
return [] if args.blank?
cond_text, cond_values = [], []
args.each do |str|
next if str.blank?
cond_text << "( %s )" % str.split.map{|w| "tag_name LIKE ? "}.join(" OR ")
cond_values.concat(str.split.map{|w| "%#{w}%"})
end
all :conditions => [cond_text.join(" AND "), *cond_values]
end
Now you can make calls such as:
Tag.search("Ruby On Rails")
Tag.search("Ruby On Rails", "Houston")
Tag.search("Ruby On Rails", "Houston", "TX")
Tag.search("Ruby On Rails", "Houston", "TX", "Blah")
Tag.search("Ruby On Rails", "Houston", "TX", "Blah", ....) # n parameters
Caveat:
The wild card LIKE searches are not very efficient(as they don't use the index). You should consider using Sphinx (via ThinkingSphinx) OR Solr(via SunSpot) if you have lot of data.
You can try to set up ferret, or if you are really bend on just using rails, try this:
# Break the search string into words
words = params[:search].blank? ? [] : params[:search].split(' ')
conditions = [[]] # Why this way? You'll know soon
words.each do |word|
conditions[0] << ["tag_name LIKE ?"]
conditions << "%#{word}%"
end
conditions[0] = conditions.first.join(" OR ") # Converts condition string to include " OR " easily ;-)
# Proceed to find using `:conditions => conditions` in your find
hope this helps =)
Sounds like you need a full text search. The best search integration right now is with Sphinx and the Thinking_Sphinx plugin. I have used it on several projects and it's super easy to setup.
You do need to install sphinx on your host so if you are using a shared host that could present some issues.
You could also use full text search in a MyISAM MySQL database, but performance on that is pretty poor.
Once you have your sphinx installed you just put what you want to index in your model and call model.search. The results will be a list of model objects. It supports will_paginate as well.
I'd suggest looking at Searchlogic if you don't want to use a separate fulltext search engine (Ferret, Sphinx, etc). It makes simple searches extremely easy, although you may not want to use it in a public facing area without lots of testing.
Also check out the Railscast on it: http://railscasts.com/episodes/176-searchlogic
1.You can do some coding in your controller post as such:-
<pre>
def show
#post = Post.find(params[:id])
#tag_counts = Tag.count(:group => :name, :order => 'updated_at DESC', :limit => 10)
respond_to do |format|
format.html # show.html.erb
format.json { render json: #post }
end
end
</pre>
2.Now make some changes in your view file:-
<pre>
<b>Tags:</b>
<%= join_tags(#post) %>
<%unless #tag_counts.nil?%>
<% #tag_counts.each do |tag_name, tag_count| %>
<tr><td><%= link_to(tag_name, posts_path(:name => tag_name)) %></td>
<td>(<%=tag_count%>)</td>
</tr><% end %>
<%end%>
</pre>
3. And one important thing is that there should be many to many relationship between tags and post.

Resources