> G'day,
> I have a project that relies heavily on pluginaweeks "state_machine"
> gem. While I would have liked to post this to a state_machine forum,
> 1. I couldn't find one and 2. this is probably a generic ruby concept
> that I just can't piece together on my own - so asking here may be
> *more* appropriate (but still less appropriate than a straight ruby
> forum... maybe).
> I have a ton of models that each have fairly complex state machines.
> state_machine defines them with blocks directly in your model class
> like so:
> state_machine :initial => :created do
> state :created
> event :review do
> transition any => :reviewing
> end
> end
> My state_machine blocks however are very large and clutter up my
> model.rb files...
IMHO, they don't *clutter* your models; they are *part of* your models.
I tend to think you want the state_machine blocks in the model files so
that you can review your state machine behaviors right along with your
methods and everything else. So I'm not sure that it's such a great
idea to do what you're asking.
However, it's not that hard. Read on for ideas!
> What I want to do is extract out all of the state machine code to
> another file that I can then "include" in my model. I know include is
> the wrong terminology in ruby.. maybe I want to modularize them?
> Whatever it's called. It's preferable (for maintainability, etc)
Why would this help maintainability? It seems to me that it would be
more maintainable to keep it all together as outlined above?
Maintainability was probably not the best word. Readability? Looking
for a better abstraction? I dunno. Having a model with only 300 lines
of code with 80 of those for a state machine -- looks ugly. There has
to be a more readable abstraction.
Now that I see how it works, I'm thinking something like:
instance_eval(File.read("states.rb"), "states.rb")
> for
> my models to look something like
> class Thing < ActiveRecord::Base
> #validations
> #callbacks
> #etc...
> line_of_code_that_loads_external_state_file_here
> #maybe eval somehow
> #maybe make a module that gets "mixed in"... i really dont know the
> right approach
> end
Well, you could take several approaches here. You could reopen the
class in a separate file...
### app/models/thing.rb
class Thing < ActiveRecord::Base
# validations
# methods
require 'thing_states'
end
### lib/thing_states.rb
class Thing < ActiveRecord::Base
state_machine stuff
end
...you could store the state machine configuration in a YAML file or
something and read it with YAML.load or whatever that function is...you
could write a wrapper function for state_machine with a shorter
syntax...
But again, I think that this is probably not a great idea. If your
state machine definitions are part of your model functionality, they
should probably be in the same model file with everything else. If your
state machines are just "clutter", then they probably shouldn't be in
your code at all. (Note all the "probably"s here -- I could well be
wrong.)
They are definitely not "clutter" I just meant that they clutter up
an otherwise readable file. I think making some sort of wrapper for
instance_eval that figures out the model name then instance evals it
from say... app/models/states/order_states.rb or somesuch.
I see your point about keeping it together but there comes a point
where an abstraction becomes necessary... I may not be at that exact
point yet, but I see it over the horizon and want to work it out now.