I've hit a snag with my college project regarding the use of the Sunspot search gem and will_paginate. I've been using sunspot in my project index controller and it was working fine but when I added pagination to the same index it created a problem. I cant seem to have both the search and pagination at the same time.
This gives me the pagination (see below):
def index
#projects = Project.all
#projects = Project.paginate :per_page => 4, :page => params[:page]
respond_to do |format|
format.html # index.html.erb
format.json { render json: #projects }
end
end
This gives me my search index (see below):
def index
#projects = Project.all
#search = Project.search do
fulltext params[:search]
end
#projects = #search.results
respond_to do |format|
format.html # index.html.erb
format.json { render json: #projects }
end
end
But when I add the pagination it doesn't work/display (see below):
def index
#projects = Project.paginate :per_page => 4, :page => params[:page]
#search = Project.search do
fulltext params[:search]
end
#projects = #search.results
respond_to do |format|
format.html # index.html.erb
format.json { render json: #projects }
end
end
The search still works but the pagination doesn't appear...
Any ideas how I get them both working together?
Many Thanks!
Answering my own question here, never occured to me to add in IF and ELSE to separate the actions in the def index....
This works perfectly...
if params[:search]
#search = Project.search do
fulltext params[:search]
end
#projects = #search.results
else
#projects = Project.all
#projects = Project.paginate(:page => params[:page], :per_page => 4)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #projects }
end
Related
I'm fairly new to Rails and I have a Ruby on Rails 3.2 application and I've integrated the Youtube_it gem seen here https://github.com/kylejginavan/youtube_it. The gem works fine and I'm able to upload the video to youtube, but it takes a while to process the video. I would like to be able to run that as a background job and redirect the user to the thank you page I have created.
I'm not sure where to call the delay method. I would like to call the delay method and then have the user redirect to the page_path('thank-you') page.
Any help would be greatly appreciated. I've searched all over for an answer.
VideosController
def upload
#video = Video.create(params[:video])
if #video
#upload_info = Video.delay.token_form(params[:video], save_video_new_video_url(video_id: #video.id))
else
respond_to do |format|
format.html { render "/videos/new" }
end
end
end
def save_video
#video = Video.find(params[:video_id])
if params[:status].to_i == 200
#video.update_attributes(youtube_id: params[:id].to_s, is_complete: true, user_id: current_user.id, approved: false)
Video.delete_incomplete_videos
else
Video.delete_video(#video)
end
#redirect_to videos_path, notice: "video successfully uploaded"
redirect_to page_path('thank-you')
end
Here is my controller.
class VideosController < ApplicationController
before_filter :authenticate_user!, only: [:new, :upload, :save_video, :destroy]
def index
if params[:category]
Video.yt_session
#videos = Video.approved.where(category_id: params[:category])
else
Video.yt_session
#videos = Video.approved
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #videos }
end
end
def show
#video = Video.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #video }
end
end
def new
#video =Video.new
#categories = Category.all
respond_to do |format|
format.html # new.html.erb
format.json { render json: #video }
end
end
def upload
#video = Video.create(params[:video])
if #video
#upload_info = Video.token_form(params[:video], save_video_new_video_url(video_id: #video.id))
else
respond_to do |format|
format.html { render "/videos/new" }
end
end
end
def save_video
#video = Video.find(params[:video_id])
respond_to do |format|
if #video.update_attributes(:youtube_id => params[:id].to_s, :is_complete => true,:user_id=>current_user.id,:approved=>false)
format.html { redirect_to page_path('thank-you') }
format.json { head :no_content }
else
format.html { Video.delete_video(#video) }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
def destroy
#video = Video.find(params[:id])
if Video.delete_video(#video)
flash[:notice] = "Video deleted."
else
flash[:error] = "We were unable to delete this video."
end
redirect_to videos_path
end
def vote_up
#video = Video.find(params[:id])
#video.update_attribute(:votes_up, (#video.votes_up.to_i + 1))
redirect_to #video
end
protected
def collection
#videos ||= end_of_association_chain.completes
end
end
You can always use background workers to do that using the like of delayed_job, but personally speaking I prefer to use Resque/beanstalkd/RabbitMQ since I can run multiple workers, concurrently.
To make your life even easier, you just try Sidekiq (https://github.com/mperham/sidekiq).
You will move your worker logic to some worker.
Include Sidekiq to your Gemfile
gem 'sidekiq'
At your controller add something like:
VideoSaverWorker.perform_async(#video.id)
The VideoSaverWorker must look something like:
class VideoSaverWorker
include Sidekiq::Worker
sidekiq_options queue: "high"
def perform(video_id)
video = Video.find(video_id)
.....
.....
end
end
Please note using this you will do the work at a background thread, but it wont redirect you to the related page.
You will need to do some workarounds, something like periodically refrishing the page till you see the changes at your view html page, or maybe you can push the changes to your webpage using Faye or Node.js.
this is my post_controller
def index
#posts = Post.all.page(params[:page]).per(2)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #posts }
end
end
this is /views/posts/index
<%= paginate #posts %>
and i recive:
NoMethodError in PostsController#index
undefined method `page' for #
I saw many themes with the same error and solution:
Kaminari.paginate_array(my_array_object).page(params[:page]).per(10)
but where should i put this?
You can put it in your controller
#posts = Kaminari.paginate_array(my_array_object).page(params[:page]).per(10)
But you also could do this:
#posts = Post.page(params[:page]).per(2)
Probably a silly question, so I apologize in advance for this:
I have an Item Controller whose index action I'm using to show all items (duh). Now, I want to filter the items that are shown (here, just ones that have 'shoes' in their titles).
Unfortunately, I am not able to define the #item = Item.find(params[:id]) statement under the index action.
I am getting the dreaded ActiveRecord::RecordNotFound in ItemsController#index ---- Couldn't find Item without an ID error.
Any ideas?
Items Controller
def index
#item = Item.find(params[:id])
#items = Item.where(#item.title =~ /shoes/i).paginate(:page => params[:page], :per_page => 30)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #items }
end
end
This is actually what you want. What you tried makes no sense.
def index
#items = Item.where("title ILIKE '%shoes%'").paginate(:page => params[:page], :per_page => 30)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #items }
end
end
Edit:
In a way to be compatible with all the supported DBs it seems you can do something like this instead
item=Item.arel_table
Item.where(item[:title].matches('%shoes%'))
I'm using sunpost gem for search in my rails project.
I have now two languages in my app:
I18n.default_locale = :en
LANGUAGES = [
['English',
'en'],
["EspaƱol".html_safe, 'es']
]
I have in my post.rb model, a language attribute that contains the value "es" for spanish language or value "en" for english language.
I have in posts_controller in index action the next method:
def index
#search = Post.solr_search do |s|
s.fulltext params[:search]
s.keywords params[:search]
s.order_by :created_at, :desc
s.paginate :page => params[:page], :per_page => 20
end
#posts = #search.results
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.js
end
end
I get the current language with I18n.locale.to_s I get with this code "es" or "en"
My question is: How can I only show the results for the language currently in use by user in my website?
Thank you very much!
It would be very helpful if you could post the searchable block in the post model. But until then, I will take a stab at it.
Your Post model should look something like the following:
class Post < ActiveRecord::Base
searchable do
...
string :language
...
end
end
Where you are indexing the language the post is written/stored in.
Then your controller you use the language field as a filter. It should look like:
def index
#search = Post.search do |s|
s.keywords params[:search]
s.with(:language, I18n.locale.to_s) if I18n.locale.present?
s.order_by :created_at, :desc
s.paginate :page => params[:page], :per_page => 20
end
#posts = #search.results
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.js
end
end
and there you have it!
I am new to rails so could use some help here. I have followed several tutorials to create a blog with comments and even some of the AJAX bells and whistles and I am stuck on something that I hope is easy. The default display for both blogs and comments is to list the oldest first. How do I reverse that to show the most recent entries and the most recent comments at the top. Don't really know if this is a function of the controller or model. I have done some customization so here is the code for the controller .rb files if it helps.
COMMENTS CONTROLLER
class CommentsController < ApplicationController
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create!(params[:comment])
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
end
POSTS CONTROLLER
class PostsController < ApplicationController
before_filter :authenticate, :except => [:index, :show]
# GET /posts
# GET /posts.xml
def index
#posts = Post.all(:include => :comments)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #posts }
format.json { render :json => #posts }
format.atom
end
end
# GET /posts/1
# GET /posts/1.xml
def show
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
# GET /posts/new
# GET /posts/new.xml
def new
#post = Post.new
respond_to do |format|
format.html { redirect_to #post}
format.js
end
end
# GET /posts/1/edit
def edit
#post = Post.find(params[:id])
end
# POST /posts
# POST /posts.xml
def create
#post = Post.new(params[:post])
respond_to do |format|
if #post.save
flash[:notice] = 'Post was successfully created.'
format.html { redirect_to(#post) }
format.xml { render :xml => #post, :status => :created, :location => #post }
else
format.html { render :action => "new" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# PUT /posts/1
# PUT /posts/1.xml
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'
format.html { redirect_to(#post) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #post.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.xml
def destroy
#post = Post.find(params[:id])
#post.destroy
respond_to do |format|
format.html { redirect_to(posts_url) }
format.xml { head :ok }
end
end
private
def authenticate
authenticate_or_request_with_http_basic do |name, password|
name == "admin" && password == "secret"
end
end
end
As jtbandes pointed out, to reverse the posts in the index, you'd change the line in your index action to read:
#posts = Post.all(:include => :comments, :order => "created_at DESC")
In order to reverse the listing of your comments, there are two possibilities.
Option 1: In your post model you can declare your relationship like so:
class Post < ActiveRecord::Base
has_many :comments, :order => "created_at DESC"
end
Option 2: In your index view, simply reverse the array of each post's comments before displaying them:
<% #posts.each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments.reverse %>
<% end %>
The options have different use cases. In option 1, you're saying that throughout your entire application, any time you refer to the comments on a post, those comments should be retrieved from the database in the specified order. You're sort of saying that this is an intrinsic property of comments in your application - posts have many comments, which are by default ordered newest first.
In option 2, you're simply reversing the comments in the index page before they're rendered. They were still retrieved in the original order (oldest first) from the database, and they'll still appear in that order anywhere else you access the comments of a post in your application.
If you're looking for a more generic way to reverse the order of the .each method, Rails has the .reverse_each method. Like so:
<% #posts.reverse_each do |post| %>
<%= render :partial => post %>
<%= render :partial => post.comments.reverse %>
<% end %>
#posts = Post.find(:all, :include => :comments, :order => "published_at DESC")
It looks like you can reverse the order using find: something like Post.find(:all, :order => "created_at DESC"). The same should apply to comments.
.reverse_each method bumping with will_paginate
here is the solution
#posts = Post.all.paginate(:order => "created_at DESC",:page => params[:page],:per_page => 5)
try use: reverse_order
Client.where("orders_count > 10").order(:name).reverse_order
this will execute the SQL:
SELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC
If no ordering clause is specified in the query, the reverse_order orders by the primary key in reverse order.
Client.where("orders_count > 10").reverse_order
which will execute:
SELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC
http://edgeguides.rubyonrails.org/active_record_querying.html#reorder