Ruby on Rails: Dynamic function name, based on database - ruby-on-rails

How can I create a dynamic function name in rails using the data in the database? I don't know if this is even possible.
here is a sample of my goal
class PageController < ApplicationController
def (PageModel.find(1)) #def stay
#codes here #codes here
end #end
end
I know the syntax is wrong. please help, thanks
Update
this function will only be called via routes, and in my routes I have this line
match "/:action", :controller => "page", :via => "get"
the function will look like this if it is manually generated
def stay
#some query
render 'stay_page', :layout => 'stay_page_layout'
end
def pleasure
#some query
render 'pleasure _page', :layout => 'pleasure _page_layout'
end

In routes.rb:
# Either this...
get "pages/:page", to: "pages#page"
# Or this, but make sure this is the last route in the file
get "/:page", to: "pages#page"
Your controller:
class PageController < ApplicationController
def page
#page = PageModel.find(params[:page])
end
end
If you just need to render different templates depending on the page, you can do this:
def page
#page = PageModel.find(params[:page])
render #page.name
end
If you need custom logic you could do something like this:
VALID_PAGES = ["contact_us"]
def page
#page = PageModel.find(params[:page])
execute(#page.name)
end
def execute(name)
if VALID_PAGES.include?(name)
send(name)
end
end
def contact_us
# do stuff
end

Assuming your PageModel have page_id and page_name, your url get page_id as an parameter, and will render with page_name.
code for controller:
class PageController < ApplicationController
def dynamic_action
page_name = PageModel.find(params[:page_id]).page_name
render "#{page_name}_page", :layout => "#{page_name}_page_layout"
end
end
route:
match '/:page_id' => 'page#dynamic_action'

Related

How to use the same method in 2 controllers?

I have a Rails 2 app with an API. I versioned and optimised the controllers but there are duplicate methods. The goal is to have the common information in only one place. So I explored the following options:
redirect from routes the non-API controller, but each controller needs it's specific hooks
module inclusion. This is my favorite but there are like quite a lot of errors thrown out and very limited time to fix things up.
eval. Put all the code in one file and eval it in both places. Done this, it works but I am not pleased by this workaround.
What would be the best to go about this?
Might be some typos lurking in here but:
class GenericController < ApplicationController
def index
#objects = params[:controller].singularize.camelcase.constantize.all()
end
def show
#object = params[:controller].singularize.camelcase.constantize.find(params[:id])
end
def new
#object = params[:controller].singularize.camelcase.constantize.new
end
def edit
#object = params[:controller].singularize.camelcase.constantize.find(params[:id])
end
def create
model = params[:controller].singularize.downcase
#object = params[:controller].singularize.camelcase.constantize.new(params[model])
if #object.save
redirect_to '/'+params[:controller]
else
render :action => 'new'
end
end
def update
model = params[:controller].singularize.downcase
#object = params[:controller].singularize.camelcase.constantize.find(params[:id])
if #object.update_attributes(params[model])
redirect_to :controller => params[:controller], :action => 'index'
else
render :action => 'edit'
end
end
def destroy
if #object = params[:controller].singularize.camelcase.constantize.find(params[:id])
#object.destroy
end
redirect_to :controller => params[:controller], :action => 'index'
end
end
Specific controllers can override those implementations as needed, but:
class ProjectsController < GenericController
# done!
end
class ScenariosController < GenericController
# done!
end

Rails if conditional in controller error

I'm wondering how can I print on the index of my project only the rooms with the :is_available column or the rooms table with the :true value (is boolean).
I can't figure out how to achieve this (Sorry but I'm new with Rails). Any advice will be very appreciate!
I've this error with my current code:
"ActiveRecord::RecordNotFound in RoomsController#home
Couldn't find Room without an ID"
Here is my rooms_controller code:
class RoomsController < ApplicationController
before_action :get_room, only: [:index, :home]
def index
end
def show
#room = Room.find(params[:id])
end
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts #rooms if Room.all(params[:is_available => :true])
end
end
def get_room
#rooms = Room.all
end
end
You already have got #rooms = Room.all, you just need to precise your query (from all to your is_available restriction).
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts #rooms.where(is_available: true)
end
end
Also, you should avoid using puts in your controller logic. Either pass variable to the view (you can change #rooms value or create new variable #available_rooms), respond_with it or log it using Rails.logger if you use puts as a debugging solution.
def index
end
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
elsif params[:is_available]
puts #rooms
end
end
def get_room
#rooms = Room.where(is_available: true)
end
Using puts in controller - not a good idea.Use view to show the data.
There are several issues you may have:
Routes
Your index method looks empty. I presume you're using "home" as a substitute
In this case, you have to know what type of action this is - a member or collection action? The reason this is important is that when you define your routes, you have to ensure you define the route in the right way. For your home route, I'd have done this:
#config/routes.rb
resources :rooms do
get "home", action: "home"
end
Scopes
You can use a scope to bring back all the values with :is_available present. This lives in the model like this:
#app/models/room.rb
Class Room < ActiveRecord::Base
scope :is_available?, -> { where(is_available: true) }
end
This will allow you to call
#room = Room.is_available?
Code
Although you've not given us any context of the error (when it happens, what you do to make it happen), this is what I would do to help fix it:
#app/controllers/rooms_controller.rb
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts Room.is_available?
end
end
This may change depending the params you send & how you send them
def home
if params[:set_locale]
redirect_to root_url(locale: params[:set_locale])
else
puts #rooms if params[:is_available] && Room.where(is_available: true)
end
end
should work.

Sweepers not working unless manually invoked, what is going on?

I have the following setup: A model called Categories. These categories are managed using ActiveAdmin. I want to cache the categories using page caching.
This is how I've setup my app/admin/categories.rb
ActiveAdmin.register Category do
controller do
cache_sweeper :category_sweeper
end
end
This is my sweeper:
class CategorySweeper < ActionController::Caching::Sweeper
observe Category
def after_save(category)
expire_cache(category)
end
def after_destroy(category)
expire_cache(category)
end
def expire_cache(category)
expire_page :controller => 'categories', :action => 'index', :format => 'json'
end
end
And here is my controller:
class CategoriesController < ApplicationController
caches_page :index
cache_sweeper :category_sweeper
respond_to :json
def index
#categories = Category.all
respond_with(#categories)
end
def show
CategorySweeper.instance.expire_cache(#category)
respond_with('manually sweeped!')
end
end
So the idea is when there is a change in the active admin the sweeper should get invoked. I set up debug.log and turns out it's working. But for some reason the cache does not expire!
But, if I do the show action (i.e. go to /categories/1.json then my manual sweeper kicks in and it works fine). So why is the sweeper only working when I invoke it and not when there is a change in the admin?
Thanks in advance,
-David
Your ActiveAdmin controller located in different namespace, see this SO question.
Shortly:
Add slash into cache expiration url code:
def expire_cache(category)
expire_page :controller => '/categories', :action => 'index', :format => 'json'
end

Rails 3: Expiring cached public/index.html page

I have the following line on my routes.rb file.
root :to => "portfolio#index"
I cached the index page as follow:
class PortfolioController < ApplicationController
caches_page :index
def index
#portfolio = Portfolio.where("featured = ? AND enabled = ?", false, true)
end
end
And the PortfolioSweeper.rb
class PortfolioSweeper < ActionController::Caching::Sweeper
observe Portfolio
def after_save(portfolio)
expire_cache(portfolio)
end
def after_destroy(portfolio)
expire_cache(portfolio)
end
private
def expire_cache(portfolio)
expire_page :controller => 'portfolio', :action => 'index'
end
end
What is happening is that the expire_page only removes the /public/portfolio.html page but NOT /public/index.html page. Can you guys think of a way to remove both files?
Try just passing it the path, like:
expire_page '/index.html'

Rails Cache Sweeper

I'm trying to implement a Cache Sweeper which would filter a specific controller action.
class ProductsController < ActionController
caches_action :index
cache_sweeper :product_sweeper
def index
#products = Product.all
end
def update_some_state
#... do some stuff which doesn't trigger a product save, but invalidates cache
end
end
Sweeper Class:
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
#expire fragment after model update
def after_save
expire_fragment('all_available_products')
end
#expire different cache after controller method modifying state is called.
def after_update_some_state
expire_action(:controller => 'products', :action => 'index')
end
end
The ActiveRecord callback 'after_save' will work fine, but the callback on the controller action 'after_update_some_state' never seems to be called.
Looks like I was just missing the controller name when trying to get the callbacks for controller actions working. My Sweeper should be:
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
#expire fragment after model update
def after_save
expire_fragment('all_available_products')
end
#expire different cache after controller method modifying state is called.
def after_products_update_some_state
expire_action(:controller => 'products', :action => 'index')
end
#can also use before:
def before_products_update_some_state
#do something before.
end
end
I think your sweeper should look like this:
class ProductSweeper < ActionController::Caching::Sweeper
observe Product
def after_save(product)
expire_cache(product)
end
def after_destroy(product)
expire_cache(product)
end
private
def expire_cache(product)
expire_fragment('all_available_products')
expire_page(:controller => 'products', :action => 'index')
end
after_index isn't a callback unless you define it.
In the controller you should specify those actions in which the sweeper should be triggered, in a restful way those actions should be create, update, destroy, so your controller declaration should look like:
class ProductsController < ActionController
caches_action :index
cache_sweeper :product_sweeper, :only => [:create, :update, :destroy]
def index
#products = Product.all
end
def create
#product = Product.new(params[:product])
if #product.save # triggers the sweeper.
# do something
else
# do something else
end
end
# update and stuff ...
end
I hope it helps you!

Resources