How to make 'sticky' posts in Rails? - ruby-on-rails

I'm still sort of new to Rails. I'm building a blog type website and would like to make some of my posts "sticky", just like Wordpress stickies (stick to the top).
I know you can order posts by its created_at column, which is what I'm doing now. But how would I have my "sticky" posts stay above my other posts no matter what its created_at date is?
Current code:
#posts = Post.all.order('created_at desc')
Everything's working fine now. There was a minor issue with my code
#posts = Post.order('sticky, created_at desc')
works fine..

Just add a boolean attribute sticky to your Post model and then do:
#posts = Post.order('sticky, created_at desc')

Try this?
In controller:
#sticky_posts = Post.where(sticky: true)
#common_posts = Post.where(sticky: false).order('created_at DESC')
In view:
<%= render :partial => 'post', locals: {posts: #sticky_post %>
<%= render :partial => 'post', locals: {posts: #common_post %>
Just make two query and it can do what you want.

You have string attribute : post_type (sticky, normal, or unpublished). If you are still using string attribute, try this :
#posts = Post.where('post_type not in (?)', 'unpublished').order('post_type desc, created_at desc')
Note :
.where('post_type not in (?)', 'unpublished')
not display post have unpublished post_type.
.order('post_type desc, created_at desc')
order post_type with descending (sticky, normal) and
created_at with descending
But that is not recommended, You should use boolean attribute, example
t.boolean :sticky
# sticky : true , normal : false
t.boolean :publish
# publish : true , unpublish : false
And you can use this on your controller :
#posts = Post.where(:publish => true).order('sticky DESC, created_at DESC')
See example :
Ruby on Rails 3.2.x - Sticky and Publish Post

Related

How can I add pagination on shopify API products with rails gem

I'm using the rails gem shopify API gem to fetch shopify products. I'm fetching products like this:
ShopifyAPI::Product.find(:all, params: { page: parmas[:page],
limit: 10,
title: params[:search]
})
this API returns products searched by title with limit 10.
So How can I add pagination on my view or can I use will_paginate gem for it?
Please help!, thanks! in advance.
I think is late for your work. But this how to it:
Example
#orders = ShopifyAPI::Order.find(:all, :params => {:status => "any", :limit => 3, :order => "created_at DESC" })
#orders.each do |order|
id = order.id
name = order.name
end
while #orders.next_page?
#orders = #orders.fetch_next_page
#orders.each do |order|
id = order.id
name = order.name
end
end
So you can create paginable array based on what you receive in each loop. The first call defines the limit for all subsequents call to fetch_next_page. In my case each page contain 3 element, you can go up to 250.
Another way is to navigate using shopify "next_page_info" parameter, so you only need to fetch the first query and include all filters, then just navigate back/fwd with page infos(previous_page_info or next_page_info).
Example 2
first_batch_products = ShopifyAPI::Product.find(:all, params: { limit: 50 })
second_batch_products = ShopifyAPI::Product.find(:all, params: { limit: 50, page_info: first_batch_products.next_page_info })
next_page_info = #orders.next_page_info
prev_page_info = #orders.previous_page_info
More info here: https://github.com/Shopify/shopify_api#pagination
Regards.
You can use Kaminari.paginate_array(*args) with array(array of Shopify products) as first argument and with option as hash, where you have to set value to total_count key.
Full example:
#paginatable_array = Kaminari.paginate_array(#shopify_products, total_count:145).page(1).per(10)
use 1 as argument to .page method, because your array will contain only 10 objects(if limit is 10 and 10 objects in view)
In view just use helper method
<%= paginate #paginatable_array %>
I hope that it will help!

Ransack search not working if there is 'space' in search term

I am using ransack for search in my rails 3.2 application using postgres as database.
I have a Invoice model and every invoice belongs_to a buyer. Below is my search form in index page.
views/invoices/index.html.erb
<%= search_form_for #search do |f| %>
<%= f.text_field :buyer_name_cont %>
<%= f.submit "Search"%>
<% end %>
And here is my controller code.
controllers/invoices_controller.rb
def index
#search = Invoice.search(params[:q])
#invoices=#search.result(:distinct => true).paginate(:page => params[:page], :per_page => GlobalConstants::PER_PAGE )
respond_to do |format|
format.html # index.html.erb
format.json { render json: #invoices }
end
end
Let's say a invoice is there of a buyer having name "Bat Man".
If I search "Bat", I get the invoice in results.
Again if I search "Man", I get the invoice in results.
But if I search "Bat Man", I don't get the invoice in results.
I know it might be something trivial but I am not able to resolve.
Update
When I tried the sql query formed directly in database using pgAdmin, I realized that in database there were multiple spaces in the buyer name, something like "Bat.space.space.space.Man".
Can something be done so that "Bat.space.Man" search also finds "Bat.space.space.space.Man" in results?
You could sanitize your data. For instance with regexp_replace(). Run in the database once:
UPDATE invoice
SET buyer = regexp_replace(buyer, '\s\s+', ' ', 'g')
WHERE buyer <> regexp_replace(buyer, '\s\s+', ' ', 'g');
And sanitize new inserts & updates likewise.
\s .. class shorthand for "white space" (including tab or weird spaces).
The 4th parameter 'g' is for "globally", needed to replace all instances, not just the first.
Ransack not support cont search for multi terms, I solved the requirement my customized way. the details as following:
Add scope to your model:
scope :like_search, ->(column, value) {
keywords = value.to_s.split.map{ |k| "%#{k}%" }
where(Array.new(keywords.size, "#{column} ILIKE ?").join(' AND '), *keywords)
}
in your view. instead of using f.text_field :buyer_name_cont provided by ransack, use normal field helper text_field_tag :buyer_name, params[:buyer_name]
then restrict your ransack in scope:
scope = Invoice.like_search(:name , params[:buyer_name])
#q = scope.ransack(params[:q])

:search => :all return empty on rails 3

i have a link_to like this:
<%= link_to "All", cars_path(:search => :all) %>
When i click him i receive this url:
localhost:3000/cars?search=all
The issue is, i have 3 records in database and don't appears nothing with the search link.
My cars_controller.rb have on index:
#cars = Car.search(params[:search])
And in the car.rb model i have a method:
def self.search(search)
result = order('new DESC')
result = joins(:model => :brand).where('brands.title LIKE ? OR models.title LIKE ? OR status LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%").order('new DESC') if search.present?
result
end
I have another methods, but i delimited to this and still not working.
Any suggestions are welcome, thank you!
In your query you are searching for an car that has 'all' in its title or brand name. Is that really what you want? And do you have any cars in your table with such name?
If you just write <%= link_to "All", cars_path %> search won't be present and you should get all cars.
When you are using same params multiply times in an query like this you can make it much shorter if you write it like this.
def self.search(search)
result = order('new DESC')
result = result.joins(:model => :brand).where('brands.title LIKE :search OR models.title LIKE :search OR status LIKE :search', search: "%#{search}%") if search.present?
result
end

Can't sort table in 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.

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