Alternatives to mixins


#1

Hi all,

I was reading James’ summary of engines in rails 2.3 (
http://rails-engines.org/news/2009/02/02/engines-in-rails-2-3/) and at
the
bottom there is

“While the code mixing mechanism is quite neat, there are other ways of
overriding the implementation of methods which are more typically
Rubyish,
and involve less magic. I’ll try and post some examples here soon.”

I’m wondering what those more Rubyish ways are. I rely on mixins in a
few
of my apps, so I’m eager to learn.

thanks,
-Andrew R.


#2

I think he meant that a better solution would be to do it manually,
and
not have the engines automagically mixin stuff for you. For example,
instead
of putting all of your methods right in your
app/controllers/controller.rb
file, put them in a module (lib/controller_methods.rb etc.) then
“include”
and/or “extend” that module in your plugins controller class.

When a parent app uses the plugin, and overrides the
app/controllers/controller.rb file, simply “include” or “extend” the
module
coming from the plugins’ lib/controller_methods.rb file.

That might not be the way James meant, but it’s something I did in my
own
apps before I even knew about Engines. It works, and it’s very clear as
to
what is happening.

Hope that helps?

Matt


#3

Here’s an example. We have a questionnaire engine, which has models

RadioField, Selectfield < QuestionWithOptions < Question < Element
Datefield, Textarea, Textfield < Question < Element

Actually, it’s on github.
http://github.com/twinge/questionnaire_engine/tree/2405f96ef12aa7c6eb84ca21370660e7bfbdcaa4/app/models

I extend that in my application at the Element level to have tags
(‘confidential’, ‘in_summary_view’, etc). Ideas how this can be done
without mixins? Require the engines element.rb in my element.rb?

-Andrew


#4

Hi Andrew,

What I’d do is put all of the methods that your plugin’s classes use, in
modules. So your Element class would look like:

class Element
include Core::Element
end

Your Question class:

class Question
include Core::Element
include Core::Question
end

etc…, that way, your app would simply do the same, without having to
worry
about the same file name problem. Does that help?

Matt


#5

Probably the simplest way, given a my_app/vendor/plugins/my_plugin/app/
models/thing.rb, is to create the file my_app/app/models/thing.rb:

require File.join(RAILS_ROOT, ‘vendor/plugins/my_plugin/app/models/
thing.rb’)

class Thing < ActiveRecord::Base
def override_something
end
end

This is basically an equivalent of what the code-mixing was doing
anyway.

James


#6

I think it’s better using “require_dependency” instead of “require” to
avoid
reloading errors in development environment, isn’t it? Or that behaviour
changed in Rails 2.3?


#7

You’re absolutely right - I meant to write that, and then completely
forgot :slight_smile:


#8

Brian Johnson wrote:

James A. wrote:

You’re absolutely right - I meant to write that, and then completely
forgot :slight_smile:

Wouldn’t it also be possible to still use the engines plugin along with
Rails 2.3 engines for the other features it provides by using:
disable_application_view_loading = false
disable_application_code_loading = false
and leaving disable_code_mixing = true
? Then you would still have code mixing, plugin migrations and copying
of asset files but Rails 2.3 would handle the load paths? Or is that a
bad idea?

Sorry, I had those settings reversed, should be:

disable_application_view_loading = true

disable_application_code_loading = true
and leaving disable_code_mixing = false


#9

James A. wrote:

You’re absolutely right - I meant to write that, and then completely
forgot :slight_smile:

Wouldn’t it also be possible to still use the engines plugin along with
Rails 2.3 engines for the other features it provides by using:
disable_application_view_loading = false
disable_application_code_loading = false
and leaving disable_code_mixing = true
? Then you would still have code mixing, plugin migrations and copying
of asset files but Rails 2.3 would handle the load paths? Or is that a
bad idea?