Rails Caching: Using sweepers for actions which require parameters - ruby-on-rails

I'm trying to use sweepers to handle my page refreshes. For refreshing index actions, etc everything works fine...but I can't seem to sweepers to interpret page parameters. If anyone can tell me what's wrong with the code below, I'd be very appreciative:
Controller:
class PostsController < ApplicationController
load_and_authorize_resource
cache_sweeper :post_sweeper, :only => [:create, :update, :destroy]
caches_page :index
caches_page :show
caches_action :edit, :new
# This refreshes cache correctly
def index
#posts = Post.all
end
# This creates cache, but does not refresh it (ever). If I place the expire_page command directly into the action (instead of the sweeper), it works fine
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
flash[:notice] = t(:post_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
The sweeper:
class PostSweeper < ActionController::Caching::Sweeper
observe Post
def after_create(record)
expire_cache_for_index(record)
end
def after_update(record)
expire_cache_for_index(record)
expire_cache_for_post(record)
expire_cache_for_edit(record)
end
def after_destroy(record)
expire_cache_for_index(record)
expire_cache_for_post(record)
expire_cache_for_edit(record)
end
private
def expire_cache_for_index(record)
expire_page :controller => 'posts', :action => 'index'
end
def expire_cache_for_post(record)
expire_page :controller => 'posts', :action => 'show', :id => record.id
end
def expire_case_for_edit(record)
expire_action :controller => 'posts', :action => 'edit', :id => record.id
end
end

If we assume you copy and pasted the code, then the typo is also in your code. Since you did not get flagged with an error by Rails, we can then assume that the sweepers are not being called. (i.e. the after_update is not being called). I would add some logger messages in to verify that that really is the case.
Questions is about Post:
Is it a decedent of ActiveRecord::Base?
Do you have other callbacks that are returning false and thus stopping the chain?
The sweeper examples on the net consistently put the cache_sweeper line after the caches_xxx lines. I'd be surprised if that makes a difference but its worth checking out.

Related

send errors to "/login/errors" when logging fails instead of going to the path "/user_sessions"

I am building an app with ruby on rails 3.1.
I have a login form correctly displayed at the url "/login". When an error occurs, I would like it to go to "login/errors" instead of "/user_sessions".
For information I am using authlogic
The model used is called "user_session".
in route.rb:
resources :user_sessions, :only => [:create, :destroy]
match 'login' => 'user_sessions#new'
root :to => redirect("/login")
in user_sessions_controller.rb:
def new
#user_session = UserSession.new
respond_to do |format|
format.html # new.html.erb
end
end
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
user = User.first(:conditions => {:email=> #user_session.email})
format.html { redirect_to :controller => 'teams', :action => 'show', :id => user.team_id }
else
format.html { render :action => "new" }
end
end
end
I have tried different things without success.
Thanks for your help.
simple solution:
match 'login' => 'user_sessions#new', as: :login_page
redirect_to login_page_path if saving was fail.

How to customize flash message based on success or failure with Inherited Resources Rails plugin?

I'm using the inherited resources plugin in a 2.3.5 Rails application and was wondering how to change the flash[:notice] (or any other flash) based on the success OR failure in my create and update actions.
So given the below, how do I add flash[:notice] = "All good" if success ... and flash[:notice] = "All bad" if failure?
Thanks
class ArticleController < InheritedResources::Base
actions :show, :create, :update
respond_to :html, :json
before_filter :authorize_upsert, :only => [:create, :update]
def create
#init new game
#article = Article.new
set_article_attributes_from_app
#article.is_published = params[:article_publish_to_web] || false
# article.game_source = #client_application
create! do |success, failure|
success.html {redirect_to(#article)}
success.json {render :json => {:id=>#article.id, :created_at=>#article.created_at, :picture_urls=> #article.assets.map { |a| root_url.chop + a.photo.url}}}
failure.html {render :action => "show"}
failure.json {render :json=>#article.errors, :status => :unprocessable_entity}
end
end
Take a look at responders on its documentation.
success.html {flash[:notice] = "Hurray!"; redirect_to(#article)}}
failure.html do
flash[:notice] = "All bad..."
render :action => "show"
end
Just two ways of doing it.

Rails: request.xml?

I would like to check whether the request is XML od HTML. When HTML the page is redirected to login form (if a user is not logged in) and when XML the user get not authorized status code.
Example:
class ApplicationController < ActionController::Base
def require_user
unless current_user
IF XML
RESPOND WITH CODE
ELSE
redirect_to :controller => :user_sessions, :action => :new, :format => params[:format]
END
return false
end
end
end
class ProductsController < ApplicationController
before_filter :require_user
...
end
You should be able to use the format delegation method:
unless (current_user)
respond_to do |format|
format.xml do
# respond with code
end
format.html do
redirect_to :controller => :user_sessions, :action => :new, :format => params[:format]
end
end
return false
end

Reverse order of display of blog entries and comments, Ruby on Rails

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

Routing to new action (Rails)

I have an action in my PostsController named 'tagged', which I want to return all posts tagged with whatever term.
In my routes.rb I have the following (at the top):
map.connect 'posts/tagged/:tag', { :controller => 'posts', :action => 'tagged', :tag => /[a-z\-]+/ }
Yet navigating to posts/tagged/yes returns a RecordNotFound error:
Couldn't find Post without an ID
In my tagged.html.erb file, I'll eventually be using the find_tagged_with method from acts_as_taggable_on_steroids, but for now I've put a simple Post.find(:all) to eliminate the possibility of error.
It seems like my map.connect is being overridden, and the same error occurs even if I comment the whole of the routes.rb file out except my new line.
Ok, because you can comment out the default routes that means your problem is not in your routes at all. It's that your tagged action in the posts controller probably has something like this.
def tagged
#post = Post.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Or perhaps if you spent a little more time it looks like this:
def tagged
#post = Post.find(params[:tagged])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Where as what you want is this:
def tagged
#post = Post.find(:all, :conditions => {:tagged => params[:tagged]})
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #post }
end
end
Anyway, you should be writing functional tests for this stuff and not testing in the browser.
Why not add a RESTful route for the "tagged" action?
map.resources :posts, :member => { :tagged => :put }

Resources