Rails 3: accept all params except a specific value - ruby-on-rails-3

I have a Rails 3.2.13 Application to maintenance.
Because of authorization rules i want to limit the find(params[:file_registry_id]) method to accept all parameters except 752. (Only user tehen should be able to get it.)
def show
if current_user.tehen?
#file_registry = FileRegistry.find(752)
else
#file_registry = FileRegistry.find(params[:file_registry_id])
end
#rubric = Rubric.find(params[:id])
#rubrics = expanded_rubrics #rubric.ancestors_with_self.collect(&:id)
set_favorites
render :action => 'index'
end
Is there a method available to filter an element (here id 752) from the params hash? Or what's the best way to go?

Simple solution:
def show
#file_registry = get_file_registry
#....
end
private
def get_file_registry
if current_user.tehen?
FileRegistry.find(752)
else
unless params[:file_registry_id] == FORBIDDEN_ID_FOR_GUEST
FileRegistry.find(params[:file_registry_id])
else
false
end
end
end
FORBIDDEN_ID_FOR_GUEST should be defined outside of the controller, for example inside of a initializer.
But I suggest to use a authorization library like CanCan (https://github.com/ryanb/cancan) where you can define permissions for every use case.

Related

How to stop a helper method from applying to a specific controller?

I have a helper_method that allows links to escape from a subdomain. However it is impacting my videos_controller, as it essentially seems to negate the 'current_event' method when not in the events controlller.
I've tried several dozen different ways over the last 4 days to make it so I can still escape my links from the subdomain, but still allow the videos_controller to work.
I think the best way to achieve this is to exclude the videos_controller from the helper method, but I'm not sure how (or if it is actually the best way forward - I'm obviously a noob!) Any suggestions please?! Relevant code below:
module UrlHelper
def url_for(options = nil)
if request.subdomain.present? and request.subdomain.downcase != 'www' and !options.nil? and options.is_a?(Hash) and options.has_key? :only_path and options[:only_path]
options[:only_path] = false
end
super
end
end
Videos_controller
def new
if current_event?
#video = current_event.videos.new
else
#video = Video.new
end
end
def create
if current_event.present?
#video = current_event.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
else
#video = current_user.videos.new(params[:video])
#video.user_id = current_user.id
key = get_key_from_the_cloud
#video.key = key
end
if #video.save
flash[:success] = "Video uploaded!"
redirect_to root_url(subdomain: => current_event.name)
else
flash[:error] = "#{#video.errors.messages}"
render :new
end
end
current_event method
def current_event
if request.subdomain.present?
#event = Event.find_by_name(request.subdomain)
end
end
Did you take a look at this post yet?
You might want to create a new function test that only does something like
module UrlHelper
def test
puts "Test is called"
end
end
If that works you know its not including that fails but it has to be the method.
Otherwise you know the module is not included and you can narrow down the search.

Rails 3: Pass options to model method

This is my Model (Subscription) Method:
def activation_codes(options = {})
if options[:first]
self.group.group_codes.first
else
self.group.group_codes
end
end
I am trying to call to this method in this fashion:
sub = Subscription.where(:subscription_limit => -1).first
sub.activation_codes {:first}
For some reason the elseis being evaluated.
You need to pass Hash to method activation_codes in order to make it work as expected, like:
sub.activation_codes({:first => 'some value'})
but you're currently passing Symbol instead.

record_timestamp = false not working from model

I want to track the last_login DateTime of my user, without changing the updated_at attribute.
So inside my Model attribut I put:
def login!(session)
session[:user_id] = id
User.record_timestamp = false
self.touch(:last_login_at)
User.record_timestamp = true
end
also tried, which is the same:
def login!(session)
session[:user_id] = id
self.last_login_at = Time.now
User.record_timestamps = false
self.save(:validate => false)
User.record_timestamps = true
end
But update_at column still is updated after each login.
It seems that User.record_timestamps = false doesn't have any effect when being called from the model directly. (I use to call this method from controller or rake tasks without any problem)
please don't tell me to use update_attribute :last_login_at, Time.now which in Rails 3.1 doesnt set the updated_at column: I'm using rails 3.0.9!
Any idea?
It's really more DRY for me to do this update from the model and not from any controller...
--------------------
[edit] Hummmmmm seems like a bug in rails: I have a nested Class SubUser < User.
When I replace User.record_timestamps = false by self.class.record_timestamps = false then it's working. It's quite strange because:
1) I'm calling #user.login! with a real class User (User.first.login!)
2) even if I were calling SubUser.first.login! the command User.record_timestamps should affect too SubUser class, right?
This is the way I did this before, please give a shot.
def login!(session)
session[:user_id] = id
class << self
def record_timestamps; false; end
end
self.last_login_at = Time.now
self.save(:validate => false)
class << self
remove_method :record_timestamps
end
end
Let me know if it helps you anyway.
I would try using update_attribute because it doesn't do validations so maybe it doesn't update the timestamps either. I'm not sure if it will work:
def login!(session)
update_attribute :last_login_at, Time.now
end

Rails 3 - Building forms from Serialized Data

I've been working on a rails project where I am needed to serialize permissions for user roles and store in the database. As far as that goes I'm all good. Now my problem comes when I want to modify the serialized data from a rails generated form.
I acted on instinct and tried with the expected behavior.
That would be to use something like this:
f.check_box :permissions_customer_club_events_read
But as no getters or setters exist for the serialized data, this doesn't work (obviously :p). Now I wonder how I would go about tackling this problem and the only thing that comes to mind is dynamically generating getter and setter methods from my serialized hash.
Example:
def permissions_customer_club_events_read=(val)
permissions[:customer][:club][:events][:read] = val
end
def permissions_customer_club_events_read
permissions[:customer][:club][:events][:read]
end
Anyone understand what I'm getting at?
Here is my Model:
class User::Affiliation::Role < ActiveRecord::Base
require 'yajl'
class YajlCoder
def dump data
Yajl.dump data
end
def load data
return unless data
Yajl.load data
end
end
serialize :permissions, YajlCoder.new
after_initialize :init
def init
## Sets base permission structure ##
self.permissions ||= YAML.load_file("#{Rails.root}/config/permissions.yml")
end
end
I suggest you have a look at something like attr_bucket. Ostensibly, this can be used to solve some inheritance annoyances, but it will also solve your problem for you. Here is the essence.
It looks like you know what all your permissions are, but you want to serialize all of them into the same database field. But within your actual rails app, you want to treat all your permissions as if they were totally separate fields. This is exactly what a solution like attr_bucket will let you do. Let's take your example, you would do something like this:
class User::Affiliation::Role < ActiveRecord::Base
attr_bucket :permissions => [:permissions_customer_club_events_read, :permissions_customer_club_events_write, :permission_do_crazy_things]
after_initialize :init
def init
## Sets base permission structure ##
self.permissions ||= YAML.load_file("#{Rails.root}/config/permissions.yml")
end
end
Now you will be able to use permissions_customer_club_events_read, permissions_customer_club_events_write, permission_do_crazy_things as if they were separate database fields (this includes using them in forms etc.), but when you actually save your objects all those fields would get 'bucketed' together and serialized into the :permissions field.
The only caveat is the serialization mechanism, I believe attr_bucket will serialize everything using YAML, whereas you were using JSON. If this doesn't matter then you're golden, otherwise you might need to patch attr_bucket to use json instead of YAML which should be pretty straight forward.
Sorry if I did not understand the question ;)
You could have a customdata module, included in your model, and use method_missing:
module CustomData
def self.included(base)
base.instance_eval do
after_save :save_data
end
def method_missing(method, *args, &block)
if method.to_s =~ /^data_/
data[method] ? data[method] : nil
else
super
end
end
def data
#data ||= begin
#get and return your data
end
end
private
def save_data
end
end
With this method, you would have to use f.check_box :data_permissions_customer_club_events_read
It's not really complete, but I hope you get the idea ;)
attr_bucket seems like a good solution too.
This worked out for me in the end, this is how I solved it.
serialize :permissions, YajlCoder.new
after_initialize :init
def init
self.permissions ||= YAML.load_file("#{Rails.root}/config/permissions.yml")['customer']
build_attributes_from self.permissions, :permissions
end
private
def build_attributes_from store, prefix, path=[]
store.each do |k,v|
if v.class == Hash
build_attributes_from v, prefix, ( path + [k] )
else
create_attr_accessors_from prefix, ( path + [k] )
end
end
end
def create_attr_accessors_from prefix, path=[]
method_name = prefix.to_s + "_" + path.join('_')
class << self
self
end.send :define_method, method_name do
self.permissions.dig(:path => path)
end
class << self
self
end.send :define_method, "#{method_name}=" do |value|
self.permissions.dig(:path => path, :value => value)
end
end
And some monkey patching for hashes...
class Hash
def dig(args={})
path = args[:path].to_enum || []
value = args[:value] || nil
if value == nil
path.inject(self) do |location, key|
location.respond_to?(:keys) ? location[key] : nil
end
else
path.inject(self) do |location, key|
location[key] = ( location[key].class == Hash ) ? location[key] : value
end
end
end
end
Now getter and setter methods are generated for all of the serialized fields.

Check what command was used inside a custom Rails 3 generator

How can you tell if a generate or destroy command has been used to invoke a custom generator?
In Rails 2 you could do this:
if options[:command] == :destroy
...
end
I want to print out some helpful information, but only when rails generate has been called, not when rails destroy is called:
if is_generating
puts "You're generated something!"
end
Thanks.
check the generator class's behavior. It seems you should get either :invoke for generate or :revoke for destroy. For example, I added this:
class PatternGenerator < Rails::Generators::NamedBase
def echo_behavior
p "generate? #{generating?}"
p "destroying? #{destroying?}"
end
protected
def generating?
:invoke == behavior
end
def destroying?
:revoke == behavior
end
end
Running this, I get:
younker % rails g pattern foo
"generate? true"
"destroying? false"
younker % rails destroy pattern foo
"generate? false"
"destroying? true"
Seems to work and makes sense, so that's my final answer.