I have written two helper methods that I wish to have these available in
all of my models. I have placed them in a module called
prep_index_string.rb which looks like this:
module PrepIndexString
# This method prepares descriptive strings that are used as
# indices for lookups. The keycase strips method leading and
# trailing spaces, squeezes out extra whitespace between words,
# and then downshifts all.
I have written two helper methods that I wish to have these available in
all of my models. I have placed them in a module called
prep_index_string.rb which looks like this:
module PrepIndexString
# This method prepares descriptive strings that are used as
# indices for lookups. The keycase strips method leading and
# trailing spaces, squeezes out extra whitespace between words,
# and then downshifts all.
#
# Do not use ! methods as they return nil under certain circumstances
#
# If the attribute passed does not respond to the to_s message then
throw
# an error. There is nothing useful we can do here.
def keycase(value)
value = value.to_s.strip.squeeze(" ").downcase
end
# This method simply upshifts the first character of every element
# separated by a word boundary in a string.
def titlecase(value)
value = value_to_s.gsub(/\b\w/){$&.upcase}
end
end
How and where is the best way to mixin these two methods for every model
(and possibly every view and controller as well) in a particular rails
project? I initially added these to application_helper.rb but have
since discovered that this is completely ignored by models. I tried
requiring "prep_index_string" and including/extending PrepIndexString at
the top of the model files but I nonetheless threw undefined method
errors on both methods whatever I tried.
It almost seems to me as if I should subclass String and mix them in
there but how should I do this for just one Rails project?
Put prep_index_string.rb in the lib/ directory. Then include the module
in all the classes you want to use the methods:
require "prep_index_string"
class SomeModelOrController
include PrepIndexString
# blah blah
end
This makes the methods available at the _instance_ level.
If you want to have them at the class level too, add the line
"extend PrepIndexString" near the include line.
If you don't wan't to manually include it in every class you can
go the hardcore route and extend ActionController::Base
and ActiveRecord::Base.
Put this in lib/prep_index_string_extension.rb:
require "prep_index_string"
class ActiveRecord::Base
include PrepIndexString
extend PrepIndexString
end
class ActionController::Base
include PrepIndexString
extend PrepIndexString
end
and require "prep_index_string_extension" in environment.rb.
And make all the methods in PrepIndexString private.
You might also consider putting it in a plugin.
# This method prepares descriptive strings that are used as
# indices for lookups. The keycase strips method leading and
# trailing spaces, squeezes out extra whitespace between words,
# and downshifts all.
NoMethodError: undefined method `keycase' for "UPERAND":String
from
/home/byrnejb/Software/Development/Projects/invert/app/models/entity.rb:27:in
`set_index_values'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:307:in
`send'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:307:in
`callback'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:304:in
`each'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:304:in
`callback'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:212:in
`create_or_update'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/base.rb:1972:in
`save_without_validation'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/validations.rb:934:in
`save_without_transactions'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:108:in
`save'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:66:in
`transaction'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:80:in
`transaction'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:100:in
`transaction'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:108:in
`save'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:120:in
`rollback_active_record_state!'
from
/usr/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:108:in
`save'
from (irb):6
Now my question becomes: where would I subclass String to add these two
methods for a specific rails project?
I need to clarify this. What I want to accomplish is to add these two
methods to the String class, but only for a particular project. What is
the recommended manner to accomplish this? I speculate that somewhere
in the load path I will need to create a class called String that
descends from String and adds these two methods. The question is where?
Class String
def keycase(value)
value = value.to_s.strip.squeeze(" ").downcase
end
def titlecase(value)
value = value_to_s.downcase.gsub(/\b\w/){$&.upcase}
end
Now my question becomes: where would I subclass String to add these two
methods for a specific rails project?
I need to clarify this. What I want to accomplish is to add these two
methods to the String class, but only for a particular project. What is
the recommended manner to accomplish this? I speculate that somewhere
in the load path I will need to create a class called String that
descends from String and adds these two methods. The question is where?
Class String
def keycase(value)
value = value.to_s.strip.squeeze(" ").downcase
end
def titlecase(value)
value = value_to_s.downcase.gsub(/\b\w/){$&.upcase}
end
end
If you want to add methods to the String class, you don't need to
create a class; you just need to re-open the existing String class
(which is what you've done above, except you've capitalized "class"
Furthermore, if you're defining the methods on the class, you
don't want them to take an argument:
class String
def keycase
strip.squeeze(" ").downcase
end
end
Typically you would put a modification like this in the lib directory,
and require the file at runtime, or you'd put it in a file in the
config/initializers directory, in which case it would be read and
loaded automatically.