Best Place to Store Model Specific Constants in Rails 3.1

Best place to store model specific constants in rails 3.1?

Something like:

class User < ActiveRecord::Base

TYPES = %w{ mom dad grandmother grandfather son }

TYPES.each_with_index do |meth, index|
define_method("#{meth}?") { type == index }
end

end

u = User.new
u.type = 4
u.mom? # => false
u.son? # => true

Appropriate place to store globals (not constants!) in Rails 3

Do you want the user to only change the color scheme for their account? If so, that setting should be stored in the database associated with that user.

If you store the value in a Ruby constant like $color in config/initializers/color.rb, it will be set and re-set for all users hitting that running instance of the Rails app. Say you have three production Rails processes running in a web server like Thin, 33% (depending on your load balancer) of the users will see the same color.

$color in an initializer should work locally but you'll have to restart your server after creating the variable.

Where would I store static/constant values in a rails application?

It depends on where you need to access them.

If you need to use them throughout your application, you can put them in environment.rb

# environment.rb
#
# other global config info
HELLO_EVERYONE = "hiz"

If you need to access them only inside a specific class, you can define them in that model.

class Test < ActiveRecord::Base
HELLO_EVERYONE = "hiz"
end

EDIT

The second case (where the constant is defined in the Test class), can also be accessed outside of the Test class, only it needs to be referenced as Test::HELLO_EVERYONE.

This may be helpful in cases where you have a list of items relevant to the domain of that object (like a list of US states) that you might use in a view (e.g. select_tag :address, :state, options_for_select(Address::STATES)). Although I might consider wrapping this inside of a class method instead of exposing the internal structure of the class.

class Address< ActiveRecord::Base
STATES = ["AL", "AK", "AZ", "AR", ...]

def self.states
STATES
end
end

Where should I store a list of select options in Rails 3?

I'd go with option 1 to start with, since it's simple, clear, and fairly DRY. I might refactor to option 2 if I ended up needing that constant in another model.

Option 3 has the potential to behave differently based on the locale, so I don't like that. If you end up forgetting to specify your format labels in a new locale, your selection list might end up being empty (or if there's a typo in one locale, it might take longer to notice, since the typo would be treated as valid for that locale). Regardless it's probably a good idea to unittest this in all your supported locales.

How to constantly keep model loaded in Rails 3.1

Ok, I think I figured out some sort of solution. It is not very impressive, but it seems to be working:

I requires to add a hack to the ActiveSupport::Dependencies.

So here is the hack listing:

    #lib/system_hacks/active_support.rb
module ActiveSupport #:nodoc:
module Dependencies #:nodoc:

#this array contains all the constants that have to be constantly loaded
mattr_accessor :constantly_loaded_files
self.constantly_loaded_files = []

#redefining the method, with additional line
def remove_unloadable_constants!
autoloaded_constants.each { |const| remove_constant const }
autoloaded_constants.clear
Reference.clear!
explicitly_unloadable_constants.each { |const| remove_constant const }
#a hack
constantly_loaded
end

#will simply make a call for each constants
#in that case they will be updated... but still in the memory
def constantly_loaded
constantly_loaded_files.each do |file|
file.to_s.classify.constantize
end
end
end
end

And in the initializers a small file to load the hack and to assign an array of constants:

  #config/initializers/model_loader.rb
require File.join(Rails.root, 'lib','system_hacks','active_support')
module ActiveSupport #:nodoc:
module Dependencies #:nodoc:
self.constantly_loaded_files = [A, B, C1, C2]
end
end

If you have any comments, I would happily listen for them.

Where to store globally shared data structures in Rails

I would use a module.

Stick it in your lib directory. (You may need to configure Rails 3 to autoload classes and modules from your lib folder. See this question.)

# lib/image_sizes.rb

module ImageSizes
def image_size_limits
{
"web" => {"maxheight" => 480, "maxwidth" => 680, "minheight" => 400, "minwidth" => 600},
"phone" => {"height" => 345, "width" => 230, "minheight" => 300, "minwidth" => 200},
"tablet" => {"height" => 680, "width" => 480, "minheight" => 600, "minwidth" => 400},
"other" => {"height" => 680, "width" => 480, "minheight" => 600, "minwidth" => 400}
}
end
end

Then in your models or controllers:

class MyModel < ActiveRecord::Base
include ImageSizes
# ...
end

class MyController < ApplicationController
include ImageSizes
# ...
end

Now, each model or controller that includes the ImageSizes module will have access to the module's methods, namely image_size_limits.

Where should I put functions that are accessed by models? -- Rails 3.1

  • for Controllers - put common methods in application_controller.rb
  • for Views - put common methods in application_helper.rb
  • for Models - monkeypatch ActiveRecord::Base to include common methods OR write a module with common model methods and include it in the models that need it OR do it in OOP way by subclassing ActiveRecord::Base with your abstract class, then inheriting all your models from this class.

To use common methods in both Model and Controller, do one of the following:

  • Write a plain ruby class, put it in /lib or elsewhere, just make sure it's loaded, then require it when you need to use its methods.
  • Extract common functionality to a gem, install it, require it when you need it. Publish it to rubygems if it's something valuable.

In rails, where to put a constant (variable?) that changes based on the current date?

I think that here you can use Rails caching. Look here and here for more details and examples.

Basicaly, you can write to cache:

Rails.cache.write('date', Date.today)

and read:

Rails.cache.read('date')

You can use it in whole Rails application (models, views, controllers, ...).

You can store any object in cache. Default caching uses memory and is availble for single Rails instance, however you can use different cache storing method.



Related Topics



Leave a reply



Submit