Add method to the String class in a Rails app - ruby-on-rails-3

I want to add a method for possessive strings with the following code:
module PossessiveHelper
def possessive
suffix = if self.downcase == 'it'
"s"
elsif self.downcase == 'who'
'se'
elsif self.end_with?('s')
"'"
else
"'s"
end
self + suffix
end
end
class String
include Possessive
end
I wonder though where and how I'm including this in a Rails app 3.2?

I like to have an initializer called monkey_patching.rb with the following:
Dir[Rails.root.join('lib', 'monkey_patching', '**', '*.rb')].each do |file|
require file.to_s
end
Then all you have to do is to add your code in a lib/monkey_patching/string.rb

You should create a rb file with the same content and put it in config/initializers.
It will get loaded during initialization of your Rails application and these new methods will be available for all string objects.

Related

Rails 3: accept all params except a specific value

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.

Rails 3: Trying to extend Action Mailer with a module

Trying to rewrite an old alias_method_chain to add a filter on outgoing emails, and it isn't working. I'm pretty sure I've leaving something out/missing something, but I don't know what.
This file is in /lib/outgoing_mail_filter.rb, which is loaded with config/initializers/required.rb
Here's the old code that worked under Rails 2:
class ActionMailer::Base
def deliver_with_recipient_filter!(mail = #mail)
unless 'production' == Rails.env
mail.to = mail.to.to_a.delete_if do |to|
!(to.ends_with?('some_domain.com'))
end
end
unless mail.to.blank?
deliver_without_recipient_filter!(mail)
end
end
alias_method_chain 'deliver!'.to_sym, :recipient_filter
end
And here's my current attempt at re-writing it:
class ActionMailer::Base
module RecipientFilter
def deliver(mail = #mail)
super
unless 'production' == Rails.env
mail.to = mail.to.to_a.delete_if do |to|
!(to.ends_with?('some_domain.com'))
end
end
unless mail.to.blank?
deliver(mail)
end
end
end
include RecipientFilter
end
When I run my tests, it doesn't even look like this is being called or anything. Any help is appreciated
I'm using mail_safe to rewrite emails in the development environment, highly recommended. You could look into it for inspiration if it doesn't fit your bill, the code is very simple.
The following code is extracted from /lib/mail_safe/rails3_hook.rb and should do what you want:
require 'mail'
module MailSafe
class MailInterceptor
def self.delivering_email(mail)
# replace the following line with your code
# and don't forget to return the mail object at the end
MailSafe::AddressReplacer.replace_external_addresses(mail) if mail
end
::Mail.register_interceptor(self)
end
end
Alternate version, registering with ActionMailer::Base instead of Mail (thanks to Kevin Whitaker for letting me know it's possible):
module MailSafe
class MailInterceptor
def self.delivering_email(mail)
# replace the following line with your code
# and don't forget to return the mail object at the end
MailSafe::AddressReplacer.replace_external_addresses(mail) if mail
end
::ActionMailer::Base.register_interceptor(self)
end
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.

Alter URL using ActiveResource

I am using ActiveResource to manage accessing an external service.
The external service has an URL like:
http://api.cars.com/v1/cars/car_id/range/range_num?filter=filter1,filter2
Here's my Car class:
class Car < ActiveResource::Base
class << self
def element_path(id, prefix_options = {}, query_options = nil)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
end
def collection_path(prefix_options = {}, query_options = nil)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
end end
self.site = "http://api.cars.com/"
self.prefix = "/v1/"
self.format = :json
end
When I set up my object to get a particular car in rails console:
> car = car.new
> car.get('1234')
I get a URL like this:
http://api.cars.com/v1/cars//1234.json
How do I get the URL to include the range and range_num elements?
Also, i don't want the .json extension on the end of the URL. I've attempted overriding the element_name and collection_name methods as described here: How to remove .xml and .json from url when using active resource but it doesn't seem to be working for me...
Thanks in advance for any ideas!
Get rid of the forward slash in the URL
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
becomes:
"#{prefix(prefix_options)}#{collection_name}#{URI.parser.escape id.to_s}#{query_string(query_options)}"

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.