Check what command was used inside a custom Rails 3 generator - ruby-on-rails-3

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.

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.

test 'where' clause using rspec

i have been learning to using rspec.
i have to test this one:
Book.where(old:false, id:user.collections.select(:book_id).group(:book_id).map(&:book_id)).map{|b|[b.name, b.id] }
what i've already done is :
#user = Fabricate(:user)
#book1 = Fabricate(:book, old:false)
#book2 = Fabricate(:book, old:true)
#collection = Fabricate(:collection, book_id:#book1.id)
#collection2 = Fabricate(:collection, book_id:#book2.id)
#user.collections << #book1 << #book2
#books = Book.where(old:false, id:#user.collections.select(:book_id).group(:book_id).map(&:book_id)).map{|b|[b.name, b.id]}
.....
it "books" do
subject[:filter].should == #books.map{|d| [d.name, d.id]}
end
it expected a book, but i got 0. did i forget something?
thanks in advance for any idea and help!
Your code is very unreadable and hard to test. You should split the execution into smaller methods.
Book.where(old:false, id:user.collections.select(:book_id).group(:book_id).map(&:book_id)).map{|b|[b.name, b.id] }
could be
class Book
def self.find_books_with_name(ids)
where(old: false, id: ids).map { |b| [b.name, b.id] }
end
end
Then you can call it with:
Book.find_books_and_name(user.collections.select(:book_id).group(:book_id).map(&:book_id))
which appears equally insane to me. Add to your user model and collection model something like
class Collection
def self.book_ids
select(:book_id).group(:book_id).map(&:book_id)
end
end
Now you have
Book.find_books_and_name(user.collections.book_ids)
and now you can (and you should) test each method separately. A failure will be easier to spot and the test itself will be much more simple, without all that coupling to various models and records.

Am I extending this inbuilt ruby class correctly?

In my rails app in lib/matrix.rb I have entered the following code to extend the inbuilt Matrix class:
module Matrix
require 'matrix'
class Matrix
def symmetric?
return false if not square?
(0 ... row_size).each do |i|
(0 .. i).each do |j|
return false if self[i,j] != self[j,i]
end
end
true
end
def cholesky_factor
raise ArgumentError, "must provide symmetric matrix" unless symmetric?
l = Array.new(row_size) {Array.new(row_size, 0)}
(0 ... row_size).each do |k|
(0 ... row_size).each do |i|
if i == k
sum = (0 .. k-1).inject(0.0) {|sum, j| sum + l[k][j] ** 2}
val = Math.sqrt(self[k,k] - sum)
l[k][k] = val
elsif i > k
sum = (0 .. k-1).inject(0.0) {|sum, j| sum + l[i][j] * l[k][j]}
val = (self[k,i] - sum) / l[k][k]
l[i][k] = val
end
end
end
Matrix[*l]
end
end
end
Is this the correct way to add methods to an existing class within the rails app? Should I have the require matrix line there?
EDIT 1: Additional info provided
I have now removed the require 'matrix' line.
If I type the following test code in a view page, it only works if I delete my lib/matrix.rb file:
<% require 'matrix' %>
<%
m = Matrix[
[0,0],
[1,1]
]
%>
<%= m.column(0) %>
Otherwise it gives the error:
undefined method `[]' for Matrix:Module
It appears that I am eliminating the default methods of the built in Matrix class when I try to extend the class. Is there a way around this error?
no you should not have to require 'matrix' here. Whoever uses your code(rails app in your case), should use require 'matrix'
To extend a core class in Rails, you simply open it, add your methods, and close it. For example, to extend the Matrix class:
class Matrix
def my_method
"New method"
end
end
You should not need to require 'matrix' in your code either. As long as the file holding your extension is in one of the autoload paths, you should have direct access to the new methods.
If you need to add a directory to your Rails autoload path, simply update /config/application.rb with the following line:
config.autoload_paths += %W(#{config.root}/app/extras) # Autoload /app/extras/*.rb

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.