How do I expire home page cache when an article is updated? - ruby-on-rails-3

I'm attempting to use a sweeper to clear the home page index action when a new article is published.
The home page cache is working fine in development environment and expires after 1 minute. However when an article is saved, the sweeper action is not triggered.
class HomeController < ApplicationController
caches_action :index, :expires_in => 1.minute
cache_sweeper :article_sweeper
def index
#articles = Article.published.limit(5)
end
end
class ArticleSweeper < ActionController::Caching::Sweeper
observe Article
def after_update(article)
expire_action(:controller => 'home', :action => 'index')
end
end
Either I've gone wrong somewhere or a different approach is needed to expire the home page cache.
My app uses ActiveAdmin to update articles, and Dalli for Memcache (as I'll be using Heroku).

Two steps to the solution:
The controller performing the changes on the model needs to have the sweeper reference, not the destination controller as shown above. In this case it is active_admin, so I added this to my admin/articles.rb file (source) instead of the home controller.
controller do
cache_sweeper :article_sweeper
end
And the controller name needs a slash
expire_action(:controller => '/home', :action => 'index')

Related

Setup devise to only have one master user

I have setup devise on a site and now the client just wants to be able to use 1 master password and not allow anyone else to create accounts. I removed the create account links from the login page and I also extended my RegistrationsController to look like this.
class CustomRegistrationsController < Devise::RegistrationsController
# used to override normal create behavior
def create
redirect_to user_session_path
end
# used to override normal new behavior. Redirects user back to the login page
def new
redirect_to user_session_path
end
end
Then in my routes file I have
devise_for :users, :path => '', :path_names => { :sign_in => 'login', :sign_out => 'logout'}, :controllers => { :registrations => "custom_registrations"}
Now I'm trying to find a way where I can either hardcode a master username and password or come up with a better approach to this.
This is by no means an elegant solution, but you could simply use a migration (or the database seed file, if the database is still new enough to be generated that way) to create a single User object with the desired login info, and add a validation on User that returns false if there's already an existing User.

Rails 3: How can I make a route helper that generates different routes depending on an object property or method?

I'm making an app in Ruby on Rails 3.1.3. I have different types of users (i.e. admin, operator, advertiser, etc...), and each has a different main (or home) page. I want to make a route helper that will give me the respective route for the home page of the current logged in user by using something like home_path. This is mainly for redirecting after certain actions (I want to redirect back to the respective home pages depending on the type of user).
I already have some methods available such as current_user (returns the current logged in user), current_user.admin? (returns true if the current logged in user is admin), current_user.operator?, etc.
Right now I'm using a helper method to do this, but it doesn't seem like a very Rails way to do it. The code follows anyway:
def home_path(params = {})
user = current_user
case user
when user.admin?
params = {:controller => 'administrators', :action => 'index'}.merge(params)
when user.advertiser?
params = {:controller => 'advertisers', :action => 'show', :id => user.advertiser_id}.merge(params)
when user.operator?
params = {:controller => 'callcenter', :action => 'index'}.merge(params)
else
params = {:controller => 'posts', :action => 'home'}.merge(params)
end
url_for(params)
end
I figure this should be done with constrained routes, but I still don't get how it could be done to depend on the .admin?, .operator?, etc. methods. Any help on this would be greatly appreciated.
Using a helper method is fine for this. It should probably end up in your controller, rather than a view helper, though, which gives it access to the current_user. With some cleanup, you can arrive at something that ain't half bad with the same idea you have now.
module DefaultHomeHelper
DEFAULT_PARAMS = { controller: :posts, action: :home }.freeze
ROLE_SPECIFIC_PARAMS = {
admin: { controller: :administrators, action: :index },
advertiser: { controller: :advertisers, action: :show },
operator: { controller: :callcenter, :action: :index }
}.freeze
def home_path(params = {})
url_for params.reverse_merge(ROLE_SPECIFIC_PARAMS[current_user.role] || DEFAULT_PARAMS)
end
end
I've made the assumption you can be more direct and ask your User object to just tell you its role instead of guessing one after the other. You will almost certainly need to tweak the code to accomodate whatever you're calling this on your user. I've also used the newer hash syntax, but if you're running or accommodating Ruby < 1.9 you will need to update. I've used symbols for the actions and controller names, too, because I like referring to objects and methods with symbols instead of strings (and controllers and actions are objects and methods).
You could do a simple include DefaultHomeHelper in your ApplicationController to use this. You can also make it available to your views with helper_method :home_path.

Why is Rails 3.2.2 Generating URLs prefixed with /assets when using redirect_to?

Well the title Question pretty much sums it up, But I'd like to detail a scenario anyways,
I've created a DemoController, (I have not created a Resource model), and my routes.rb looks like this:
DispatchMe::Application.routes.draw do
root to: "demo#index"
end
From the demo controller I'm dong the following:
class DemoController < ApplicationController
def index
redirect_to :action => 'show'
end
def show
end
end
There is a file in: app/views/demo/show.html.erb of course, And I'd expected that template to be rendered but instead I'm getting the following error:
ActionController::RoutingError (No route matches [GET] "/assets")
and this URL is generated as a result from the redirect:
/assets?action=show&controller=demo
Am I missing something here? I thought rails was supposed to render the action's template for such cases.
Note. I understand that If I create a route like get 'show' => "demo#show" and call redirect_to show_path it'll work just fine, But I need to know if that's mandatory?
Thank you very much!
For the desired behavior, use render instead of redirect_to:
class PagesController < ApplicationController
def index
render :action => "show"
end
def show
end
end
EDIT:
You can use redirect_to on other actions, but from what I can tell, the index action sets the base path. To simplify route definition, use resources :controller_name. You can view the routes generated by resources by typing rake routes in your command line.
Example:
demo_controller.rb
class DemoController < ApplicationController
def index
end
def show
redirect_to :action => 'index'
end
end
routes.rb
DispatchMe::Application.routes.draw do
root to: "demo#index"
resources :demo
end
development.log
Started GET "/demo/show" for 127.0.0.1 at 2012-04-04 14:55:25 -0400
Processing by DemoController#show as HTML
Parameters: {"id"=>"show"}
Redirected to http://dispatch.dev/
Completed 302 Found in 0ms (ActiveRecord: 0.0ms)

setting config.action_controller.perform_caching = true breaks routes in rails 3.2.1 app

I am experiencing extremely strange behaviour in Rails 3.2.1
I have some resources that do not have show actions.
For example:
resources :homes, :except => [:show]
In my controller I say:
def update
#domain = Domain.where(:domain => request.domain.split('.').first).first
#home = Home.find(params[:id])
if #home.update_attributes(params[:home])
expire_page :action => :index
redirect_to(admin_path(#domain), :notice => "Updated.")
else
render :action => "edit"
end
end
and all is hunky dory in development.
But in production rails consistently tries to redirect to (the non existent) show action, despite the obvious redirect_to. It's as if this method is ignored totally. In fact I can try and redirect to any path in the app and it will be ignored. As soon as I set perform_caching to false in production.rb the routes begin to behave as expected again! Any ideas why this is happening and how I can make it stop!? Obviously I could turn off caching, but I need the pages to be cached for performance reasons.
Thanks for reading.

rails caching: expire_action in another namespace

My application is using a namespace for administrative purposes. I recently tried to start using action caching however I ran into some problems trying to expire the cache using expire_action. Basically I have a index action in my default namespace newsposts controller that is cached using action caching like this:
class NewspostsController < ApplicationController
caches_action :index, :layout => false
def index
#posts = Newspost.includes(:author).order("created_at DESC").limit(5)
end
end
This caches the view under views/host/newsposts.
The default namespace has no actions for modifying data, they are all in my admin namespace. In my Admin::NewspostsController I am trying to expire this cache in the create action like this:
expire_action(:controller => 'newsposts', :action => 'index')
however this will expire a cache file located under views/host/admin/newsposts. Obviously it can not work since im in the admin namespace and rails is (rightfully) looking to expire cache for this namespace. Sadly I can not pass a namespace parameter to the axpire_action method, so how can i expire the action cache in another namespace?
after some more digging I finally found the solution. It's a bit hinted in the url_for method:
In particular, a leading slash ensures no namespace is assumed. Thus, while url_for :controller => 'users' may resolve to Admin::UsersController if the current controller lives under that module, url_for :controller => '/users' ensures you link to ::UsersController no matter what.
So basically,
expire_action(:controller => '/newsposts', :action => 'index')
Will expire in the default namespace, and
expire_action(:controller => 'admin/newsposts', :action => 'index')
in the admin namespace (when in default).
RailsCast
One additional note I learned, if you want to expire a specific format, such as XML, JSON, etc., just
expire_action(:controller => '/newsposts', :action => 'index', :format => 'xml')
or whatever format you want. It look me a while to figure out.