A lot of the built-in Rails classes have configuration options that can be set in environment.rb, but there doesn''t seem to be any standard way of doing the same thing for your own classes. The following are my initial thoughts on solving this, some simple code, and a few related questions. Let''s say I have a model called MyModel. In MyModel, I''d like to be able to do something like this: class MyModel include Configurable config_attr :example_attribute, "Here''s a default value" def my_method p config.example_attribute end end Then, in environment.rb: MyModel.configure do self.example_attribute = "Here''s the configured value" end There''s code at the end of the e-mail to implement a simple version of this. The questions: 1) How do I work around reloadable classes? The old Rails approach to adding configuration was: class MyModel @@example_attribute = "Here''s a default value" cattr_accessor :example_attribute end and in environment.rb: MyModel.example_attribute = "Here''s the configured value" This dies for model classes because MyModel is trashed and reloaded on each request, overwriting the value set in environment.rb with the default one after the first request. My code below suffers from the same problem. Anyone got any ideas on neat ways to work around this? I can think of a couple of approaches, but they''re all really ugly. 2) Would something along these lines be a possibility for inclusion in a future version of Rails? I know it''s far from being rocket science, but with the proliferation of plugins, engines, etc. it would be nice to have a standard way that this is done, if only so that you know where to look for configuration when using third-party code. 3) What do people think of the API approach I''ve suggested? I''m trying to make it as simple as possible, not force you to manually define a separate class or module just to hold configuration, but still do strict config checking in environment.rb. Cheers, Pete Yandell module Configurable def self.included(base) base.class_eval do @@config = Class.new unless defined?(@@config) cattr_reader :config end base.extend(ClassMethods) end module ClassMethods def config_attr(name, value) config.cattr_accessor name config.send("#{name.to_s}=".to_sym, value) end def configure(&block) block.bind(config).call end end end
This sort of functionality comes with Rails Engines. Check it out, it''s pretty similar. -jeff On 4/3/06, Pete Yandell <pete@notahat.com> wrote:> A lot of the built-in Rails classes have configuration options that > can be set in environment.rb, but there doesn''t seem to be any > standard way of doing the same thing for your own classes. The > following are my initial thoughts on solving this, some simple code, > and a few related questions. > > Let''s say I have a model called MyModel. In MyModel, I''d like to be > able to do something like this: > > class MyModel > include Configurable > > config_attr :example_attribute, "Here''s a default value" > > def my_method > p config.example_attribute > end > end > > Then, in environment.rb: > > MyModel.configure do > self.example_attribute = "Here''s the configured value" > end > > There''s code at the end of the e-mail to implement a simple version > of this. > > > The questions: > > 1) How do I work around reloadable classes? > > The old Rails approach to adding configuration was: > > class MyModel > @@example_attribute = "Here''s a default value" > cattr_accessor :example_attribute > end > > and in environment.rb: > > MyModel.example_attribute = "Here''s the configured value" > > This dies for model classes because MyModel is trashed and reloaded > on each request, overwriting the value set in environment.rb with the > default one after the first request. My code below suffers from the > same problem. > > Anyone got any ideas on neat ways to work around this? I can think of > a couple of approaches, but they''re all really ugly. > > > 2) Would something along these lines be a possibility for inclusion > in a future version of Rails? I know it''s far from being rocket > science, but with the proliferation of plugins, engines, etc. it > would be nice to have a standard way that this is done, if only so > that you know where to look for configuration when using third-party > code. > > > 3) What do people think of the API approach I''ve suggested? I''m > trying to make it as simple as possible, not force you to manually > define a separate class or module just to hold configuration, but > still do strict config checking in environment.rb. > > > Cheers, > > Pete Yandell > > > module Configurable > def self.included(base) > base.class_eval do > @@config = Class.new unless defined?(@@config) > cattr_reader :config > end > > base.extend(ClassMethods) > end > > module ClassMethods > def config_attr(name, value) > config.cattr_accessor name > config.send("#{name.to_s}=".to_sym, value) > end > > def configure(&block) > block.bind(config).call > end > end > end > > _______________________________________________ > Rails-core mailing list > Rails-core@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails-core >-- Jeff Lindsay http://blogrium.com/
I''ve done a lot of playing with engines, and the config system has a few things that I don''t like: First, it seems to require you to have a module into which to put your config, so the same approach is not really applicable to something as simple as a model class. I don''t want to have to manually declare a separate module for every class that needs some config. (Please correct me if my understanding of this is wrong.) Second, it stores everything in a hash. That means that if I misspell a config variable in environment.rb, I''ll only find out about it when the value is wrong at runtime. I''d much rather have the error show up when loading environment.rb, as it does in my example. Third, it''s fussy about order of loading. From the docs: "Often you might want a different configuration depending on which environment your application is running – development, production or testing. Unfortunately, these files are also loaded before any plugin is, so you need to manually create the CONFIG hash and assign keys/ values as you need." Having to fiddle with the internals like that is too complicated. On 04/04/2006, at 1:17 PM, Jeff Lindsay wrote:> This sort of functionality comes with Rails Engines. Check it out, > it''s pretty similar. > > -jeff > > On 4/3/06, Pete Yandell <pete@notahat.com> wrote: >> A lot of the built-in Rails classes have configuration options that >> can be set in environment.rb, but there doesn''t seem to be any >> standard way of doing the same thing for your own classes. The >> following are my initial thoughts on solving this, some simple code, >> and a few related questions. >> >> Let''s say I have a model called MyModel. In MyModel, I''d like to be >> able to do something like this: >> >> class MyModel >> include Configurable >> >> config_attr :example_attribute, "Here''s a default value" >> >> def my_method >> p config.example_attribute >> end >> end >> >> Then, in environment.rb: >> >> MyModel.configure do >> self.example_attribute = "Here''s the configured value" >> end >> >> There''s code at the end of the e-mail to implement a simple version >> of this. >> >> >> The questions: >> >> 1) How do I work around reloadable classes? >> >> The old Rails approach to adding configuration was: >> >> class MyModel >> @@example_attribute = "Here''s a default value" >> cattr_accessor :example_attribute >> end >> >> and in environment.rb: >> >> MyModel.example_attribute = "Here''s the configured value" >> >> This dies for model classes because MyModel is trashed and reloaded >> on each request, overwriting the value set in environment.rb with the >> default one after the first request. My code below suffers from the >> same problem. >> >> Anyone got any ideas on neat ways to work around this? I can think of >> a couple of approaches, but they''re all really ugly. >> >> >> 2) Would something along these lines be a possibility for inclusion >> in a future version of Rails? I know it''s far from being rocket >> science, but with the proliferation of plugins, engines, etc. it >> would be nice to have a standard way that this is done, if only so >> that you know where to look for configuration when using third-party >> code. >> >> >> 3) What do people think of the API approach I''ve suggested? I''m >> trying to make it as simple as possible, not force you to manually >> define a separate class or module just to hold configuration, but >> still do strict config checking in environment.rb. >> >> >> Cheers, >> >> Pete Yandell >> >> >> module Configurable >> def self.included(base) >> base.class_eval do >> @@config = Class.new unless defined?(@@config) >> cattr_reader :config >> end >> >> base.extend(ClassMethods) >> end >> >> module ClassMethods >> def config_attr(name, value) >> config.cattr_accessor name >> config.send("#{name.to_s}=".to_sym, value) >> end >> >> def configure(&block) >> block.bind(config).call >> end >> end >> end >> >> _______________________________________________ >> Rails-core mailing list >> Rails-core@lists.rubyonrails.org >> http://lists.rubyonrails.org/mailman/listinfo/rails-core >> > > > -- > Jeff Lindsay > http://blogrium.com/ > _______________________________________________ > Rails-core mailing list > Rails-core@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails-core
Regarding the first, a class is a module, so you shouldn''t have a problem using them with model classes. The second issue is understandable, and may be be a good reason not to use them. The third is understandable too, but so far hasn''t been too annoying. This is something that might get improved... if you have ideas, Engines is taking patches. : ) But anyway, I just wanted to point out a similar system, either so you don''t end up reinventing or to inspire you with new ideas. -jeff On 4/3/06, Pete Yandell <pete@notahat.com> wrote:> I''ve done a lot of playing with engines, and the config system has a > few things that I don''t like: > > First, it seems to require you to have a module into which to put > your config, so the same approach is not really applicable to > something as simple as a model class. I don''t want to have to > manually declare a separate module for every class that needs some > config. (Please correct me if my understanding of this is wrong.) > > Second, it stores everything in a hash. That means that if I misspell > a config variable in environment.rb, I''ll only find out about it when > the value is wrong at runtime. I''d much rather have the error show up > when loading environment.rb, as it does in my example. > > Third, it''s fussy about order of loading. From the docs: > > "Often you might want a different configuration depending on which > environment your application is running – development, production or > testing. Unfortunately, these files are also loaded before any plugin > is, so you need to manually create the CONFIG hash and assign keys/ > values as you need." > > Having to fiddle with the internals like that is too complicated. > > On 04/04/2006, at 1:17 PM, Jeff Lindsay wrote: > > > This sort of functionality comes with Rails Engines. Check it out, > > it''s pretty similar. > > > > -jeff > > > > On 4/3/06, Pete Yandell <pete@notahat.com> wrote: > >> A lot of the built-in Rails classes have configuration options that > >> can be set in environment.rb, but there doesn''t seem to be any > >> standard way of doing the same thing for your own classes. The > >> following are my initial thoughts on solving this, some simple code, > >> and a few related questions. > >> > >> Let''s say I have a model called MyModel. In MyModel, I''d like to be > >> able to do something like this: > >> > >> class MyModel > >> include Configurable > >> > >> config_attr :example_attribute, "Here''s a default value" > >> > >> def my_method > >> p config.example_attribute > >> end > >> end > >> > >> Then, in environment.rb: > >> > >> MyModel.configure do > >> self.example_attribute = "Here''s the configured value" > >> end > >> > >> There''s code at the end of the e-mail to implement a simple version > >> of this. > >> > >> > >> The questions: > >> > >> 1) How do I work around reloadable classes? > >> > >> The old Rails approach to adding configuration was: > >> > >> class MyModel > >> @@example_attribute = "Here''s a default value" > >> cattr_accessor :example_attribute > >> end > >> > >> and in environment.rb: > >> > >> MyModel.example_attribute = "Here''s the configured value" > >> > >> This dies for model classes because MyModel is trashed and reloaded > >> on each request, overwriting the value set in environment.rb with the > >> default one after the first request. My code below suffers from the > >> same problem. > >> > >> Anyone got any ideas on neat ways to work around this? I can think of > >> a couple of approaches, but they''re all really ugly. > >> > >> > >> 2) Would something along these lines be a possibility for inclusion > >> in a future version of Rails? I know it''s far from being rocket > >> science, but with the proliferation of plugins, engines, etc. it > >> would be nice to have a standard way that this is done, if only so > >> that you know where to look for configuration when using third-party > >> code. > >> > >> > >> 3) What do people think of the API approach I''ve suggested? I''m > >> trying to make it as simple as possible, not force you to manually > >> define a separate class or module just to hold configuration, but > >> still do strict config checking in environment.rb. > >> > >> > >> Cheers, > >> > >> Pete Yandell > >> > >> > >> module Configurable > >> def self.included(base) > >> base.class_eval do > >> @@config = Class.new unless defined?(@@config) > >> cattr_reader :config > >> end > >> > >> base.extend(ClassMethods) > >> end > >> > >> module ClassMethods > >> def config_attr(name, value) > >> config.cattr_accessor name > >> config.send("#{name.to_s}=".to_sym, value) > >> end > >> > >> def configure(&block) > >> block.bind(config).call > >> end > >> end > >> end > >> > >> _______________________________________________ > >> Rails-core mailing list > >> Rails-core@lists.rubyonrails.org > >> http://lists.rubyonrails.org/mailman/listinfo/rails-core > >> > > > > > > -- > > Jeff Lindsay > > http://blogrium.com/ > > _______________________________________________ > > Rails-core mailing list > > Rails-core@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails-core > > _______________________________________________ > Rails-core mailing list > Rails-core@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails-core >-- Jeff Lindsay http://blogrium.com/
Let me sharpen up my first question, because I think it''s essential no matter how you approach this: If I have a class that includes Reloadable, how can I declare a class variable (or equivalent thereof) that persists across reloads of the class? Cheers, Pete Yandell
Oh I see! I know I don''t have an answer for that, but it''s an interesting problem. -jeff On 4/3/06, Pete Yandell <pete@notahat.com> wrote:> Let me sharpen up my first question, because I think it''s essential > no matter how you approach this: > > If I have a class that includes Reloadable, how can I declare a class > variable (or equivalent thereof) that persists across reloads of the > class? > > Cheers, > > Pete Yandell > _______________________________________________ > Rails-core mailing list > Rails-core@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails-core >-- Jeff Lindsay http://blogrium.com/
On 4/4/06, Pete Yandell <pete@notahat.com> wrote:> Let me sharpen up my first question, because I think it''s essential > no matter how you approach this: > > If I have a class that includes Reloadable, how can I declare a class > variable (or equivalent thereof) that persists across reloads of the > class? >Short answer? You can''t. We use the following: class Foo < ActiveRecord::Base cattr_accessor :something @something="default which makes sense for development and test" end With the defaults overriden in production.rb. I think the simplest solution would be to add something like config.after_initialize which gets called after the reset_application! method? Would that be enough for you? -- Cheers Koz
Hi Pete, class Foo include Reloadable::Subclasses end class Bar < Foo end Bar will be reloaded on each request, while the superclass Foo will not. Regards, Trevor -- Trevor Squires http://somethinglearned.com On 3-Apr-06, at 11:43 PM, Pete Yandell wrote:> Let me sharpen up my first question, because I think it''s essential > no matter how you approach this: > > If I have a class that includes Reloadable, how can I declare a > class variable (or equivalent thereof) that persists across reloads > of the class? > > Cheers, > > Pete Yandell > _______________________________________________ > Rails-core mailing list > Rails-core@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails-core