How to generate an array of controller actions in Ruby on Rails? - ruby-on-rails

In my Rails 4 app I have a number of static pages that should either be indexable by Google or not. I am using a variable indexable for this but there's probably a better way:
class PagesController < ApplicationController
def home
indexable = true
end
def about_us
indexable = true
end
def secret_stuff
indexable = false
end
end
How can I generate an array of all the pages that are indexable?
I tried doing this in a helper but it's not working:
def indexable_pages
array = []
PagesController.instance_methods(false).each do |action|
if action.indexable == true # this won't work of course
array << action
end
end
array
end
Thanks for any help.

Maybe a before_filter would make sense?
class PagesController < ApplicationController
before_filter :set_indexable, except: [:secret_stuff]
def home
end
def about_us
end
def secret_stuff
end
private
def set_indexable
#indexable = true
end
end

Related

Should static pages have access to cookies in rails controller and routes.rb?

I'm sure this is an obvious question but I just don't understand why this isn't working.
I'm finding that my static pages defined in the routes.rb file don't seem to have access to cookies? Is that correct? I'm trying to read the value of a cookie but the pages below seem to return a null object.
My routes.rb contains the following:
scope controller: :static do
get :about
get :terms
get :privacy
get :cookies
get :returns
get :delivery
end
For completeness here is the Static Controller:
# frozen_string_literal: true
class StaticController < ApplicationController
before_action :find_order
def index; end
def about; end
def pricing
redirect_to root_path, alert: t('.no_plans') unless Plan.without_free.exists?
end
def terms; end
def privacy; end
def cookies; end
def returns; end
def delivery; end
end
And this is how the cookie is set:
class OrdersController < ApplicationController
before_action :find_order
def add_hamper
#order ||= Order.create!(
ordernum: find_next_order_number,
user: current_user,
basket: true
)
#order.hampers << Hamper.friendly.find(params[:id])
update_order_total(#order)
if current_user&.custaddress
#order.update(custaddress: current_user.custaddress)
else
cookies[:ordernum] = #order.ordernum
end
redirect_to order_path(#order.ordernum)
# Update basket in Navbar
# Save the information as a cookie reference if they are not signed in
end
At the start of each controller I have a before_action to find an order if it exists in the DB or Cookie. For all other controllers, the find_order method is working. For the StaticController, there seems to be no access to the cookies.
Here is my find_order as defined in ApplicationController:
def find_order
#order = if current_user
Order.where(
user: current_user,
basket: true
).first
else
if cookies.dig[:ordernum]
Order.where(
ordernum: cookies[:ordernum],
basket: true
).first
end
end
end
helper_method :find_order
I've had to add the check for cookies and then if cookies[:ordernum] to stop it from failing on the static pages.
Thanks for any help with this.
PS. If anyone feels the above code could be better ... please let me know! There must be a nicer way to achieve this. It feels a little clunky.

Rails: Access cookies in a class in a helper

I have a ruby class in a rails helper and inside that class I cannot access the ActiveController cookies method. I have looked at this question and it doesn't solve my problem and I'm not doing what that guy is since my ruby class is in the scope of the controller and is only ever called by it. What's the best way to get rid of the
NameError (undefined local variable or method `cookies` for #<CartHelper::CartObject:...>):
app/helpers/cart_helper.rb:##:in `save`
app/helpers/cart_helper.rb:##:in `add_product`
app/controllers/cart_controller.rb:##:in `add`
in my helper? (I'm also open to suggestions on how to make this more Ruby-y approach wise)
module CartHelper
class CartObject
def load (cart)
# converts from json
end
private def save
cookies.signed.permanent[:cart] = dump
end
private def dump
# converts to json
end
def add_product (product)
# ...
save
end
def remove_product (product)
# ...
save
end
end
def get_cart
return CartObject.new if cookies.signed.permanent[:cart].nil?
CartObject.load(cookies.signed.permanent[:cart])
end
end
and CartHelper is included in the application controller of course
class CartController < ApplicationController\
skip_before_action :verify_authenticity_token, only: [:add]
def view
cart = get_cart
#products = cart.products
end
def add # only by ajax
cart = get_cart
cart.add_product(Oj.strict_load(params[:product]))
head 200
end
def remove
cart = get_cart
cart.remove_product(params['rem'])
flash['success'] = 'Product removed.'
redirect_to '/cart'
end
end

call service method from a controller following correct factory patterns

I have the following class
class EvaluateService
def initialize
end
def get_url
end
def self.evaluate_service
#instance ||= new
end
end
class CheckController < ApplicationController
def index
get_url = EvaluateService.get_url
end
end
The problem here is that i know that i can do evaluate_service = EvaluateService.new and use the object evaluate_service.get_url and it will work fine but i also know that some frown upon the idea of initializing the service object this way and rather there is a way of initializing it via a call, send method in the service class.
Just wondering how do i do this?
I think what you're looking for is something like:
class Evaluate
def initialize(foo)
#foo = foo
end
def self.call(foo)
new(foo).call
end
def call
url
end
private
def url
# Implement me
end
end
Now you can do this in your controller:
class CheckController < ApplicationController
def index
#url = Evaluate.call(params)
end
end
The reason some prefer #call as the entry point is that it's polymorphic with lambdas. That is, anywhere you could use a lambda, you can substitute it for an instance of Evaluate, and vice versa.
There are various ways to approach this.
If the methods in EvaluateService don't need state, you could just use class methods, e.g.:
class EvaluateService
def self.get_url
# ...
end
end
class CheckController < ApplicationController
def index
#url = EvaluateService.get_url
end
end
In this scenario, EvaluateService should probably be a module.
If you want a single global EvaluateService instance, there's Singleton:
class EvaluateService
include Singleton
def get_url
# ...
end
end
class CheckController < ApplicationController
def index
#url = EvaluateService.instance.get_url
end
end
But global objects can be tricky.
Or you could use a helper method in your controller that creates a service instance (as needed) and memoizes it:
class EvaluateService
def get_url
# ...
end
end
class CheckController < ApplicationController
def index
#url = evaluate_service.get_url
end
private
def evaluate_service
#evaluate_service ||= EvaluateService.new
end
end
Maybe even move it up to your ApplicationController.

What is the Rails 4 way to deal with filters?

Background: I have a few filters which have to be available through every CRUD page on the system: search, livesearch, column sorting and pagination;
This is what I currently have:
.lib/record_filters.rb
module RecordFilters
##valid_directions = %w[asc desc]
def search_for(record)
record.present? ? where('name LIKE ?', record+"%") : all
end
def records_matching(search_term)
where('name LIKE ?', search_term+"%").map(&:name)
end
def order_records_by(attribute, direction)
order(sort_table_by(attribute) +" "+ sort_records_order_by(direction))
end
private
def sort_table_by(attribute)
column_names.include?(attribute) ? attribute : "name"
end
def sort_records_order_by(direction)
##valid_directions.include?(direction) ? direction : "asc"
end
end
./app/models/ticket_type.rb
class TicketType < ActiveRecord::Base
include RecordFilters
validates_presence_of :name
validates_uniqueness_of :name
end
./app/controllers/ticket_types_controller.rb
class TicketTypesController < ApplicationController
before_action :set_ticket_type, only: [:show, :edit, :update, :destroy]
def index
#ticket_types = TicketType.search_for(params[:search]).order_records_by(params[:sort], params[:direction]).paginate(per_page: 12, page: params[:page])
respond_to do |format|
format.html
format.js
format.json { render json: TicketType.records_matching(params[:term]) }
end
end
...
end
./config/application.rb
...
config.autoload_paths << "#{Rails.root}/lib"
The problem: Upon accessing the index on the browser, Rails returns NoMethodError for search_for
Question: What is the Rails Way to implement such filters? What am I doing wrong?
Thanks!
This is because Ruby's include will add the module's methods as instance methods:
module A
def value
5
end
end
class B
include A
end
puts B.new.a # prints 5
puts B.a # fails
If you want them as class methods, like the class object itself was extended, use extend:
method A
def value
5
end
end
class C
extend A
end
puts C.a # prints 5
puts C.new.a # fails
You can also, if you really want include, define some new methods in the module's included callback:
module A
def self.included(mod)
# mod is whatever (module or class) included A.
# in this case, it's B.
mod.class_eval do
def self.value
"class"
end
# there's no reason to do this here, instead of
# in the module itself, but just for demonstration purposes:
def inst
"inst"
end
end
end
end
class B
include A
end
puts B.value # prints "class"
puts B.new.inst # prints "inst"
Your methods are getting added as instance methods, but you're calling them like class methods, I'd recommend you look into http://api.rubyonrails.org/classes/ActiveSupport/Concern.html to implement the concern pattern for your models.

Rails cancan gem for not restfull controller

Is it possible to use cancan load_and_authorize_resource for Controller with different name then model?
I mean:
Controller name -> EntityPropertiesController
Model name -> Property
I don't found good way. So there is work around solution
class EntityPropertiesController < ApplicationController
before_filter :authenticate_user!
def index
check_permission
end
def new
check_permission
...
end
def create
check_permission
...
end
...
protected
def check_permission
not_found unless (current_user.admin? || current_user.moderator?)
end
end

Resources