22

I have two rails apps running off the same database, one which runs the client and one which provides an admin interface.

Both the apps have the exact same models defined save for small number of differences. Its tiresome for me to duplicate the vast majority of changes in the models on to both apps.

One way for two apps to use the same model info is to symlink the model folder from one app to the other, but I cant do that due to the few differences in code (e.g an extra validation on the client).

Is there a simple way I can move out the differences so I can keep the common code in one place?

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
desheikh
  • 286
  • 4
  • 7

7 Answers7

6

Why not doing it OOP way, e.g. creating a separate base class (in a separate directory) and then inheriting from it in both projects, so the differences are in the inherited class.

So, you have

class BaseModel < ActiveRecord::Base

in "common" subdirectory, and then you have

class AdminBaseModel < Common::BaseModel

in admin project and

class UserBaseModel < Common::BaseModel

you might need

set_table_name "basemodel"

so Rails knows which table to open.

sth
  • 222,467
  • 53
  • 283
  • 367
haimg
  • 4,547
  • 35
  • 47
6

svn:externals or git submodules are definitely the way to go for this sort of situation.

Of course, you'll want to be able to test them in both apps, so you should share your model tests or specs as well. But remember that models often depend on plugins, so you'll want to share your plugins folder, too. And you probably want the same gems and the same version of Rails, so your best bet is to share all of vendor. Oh, and sometimes your code in lib modifies your models, so you'll want to share that. Oh, and be sure to share any custom configuration in the environment files.

And you'll want to have a continuous integration server set up to run your test suite on both applications in case changes to the model tier in your master application break your other application.

But I mean, once all that is worked out, svn:externals or git submodules are definitely the way to go for this sort of situation.

Update (some years later)

Rails Engines are probably the best bet currently for reliably sharing model code between multiple applications. They can be gemified and included in the Gemfile of each application.

Ian Terrell
  • 10,667
  • 11
  • 45
  • 66
  • 1
    I take it your comment is meant sarcastically - but what would be a proper solution here? – Patrick Glandien Jun 27 '12 at 16:30
  • 3
    I'm a little surprised I wrote that, actually. Oh how the years mellow you out. I've been on a project where the above was the route taken, but that was ages ago. At this point, Rails engines are absolutely mature enough to handle this use case. I've updated the answer to reflect that. – Ian Terrell Jun 28 '12 at 19:52
  • I followed the advice on sharing models by moving it into an engine. I have an API engine that would need models located in the "Core" engine, however, I am having difficulty including the Core engine in my API engine. – Karan Aug 18 '13 at 15:00
4

I work on a project that has a similar issue and we used svn:externals to share the model code between two apps.

Basically you have the models diretory in one svn project and use an external in the other project to share the code. You can edit code in either project and it will be updated when you run svn up in the other project.

As far as Rails and your build scripts are concerned the two models directories are completely separate.

Joe Mahoney
  • 903
  • 6
  • 14
  • Thanks for the svn tip but the problem I have with sharing my models is that a few of them have slight differences (for example an extra method on the admin side). Im wondering how i can move the extra methods out so the models can be shared without issue. – desheikh Mar 23 '09 at 09:36
  • This seems similar to git-submodules – Pratik Khadloya May 06 '13 at 21:03
2

You can treat one rails project as a gem, then you can use it in other rails project by add the model path to its load path.

Here's an example, i think you can get it, though it's written in chinese. http://mvj3.github.com/2011/09/13/multiple_rails_apps_sharing_models_folder/

mvj3
  • 21
  • 4
2

Yes, symlink the models directory, but then add an environment variable to your environment.rb for each instance. Then your models can know which instance is using it and include additional validations or what not.

in environment.rb:

APP_INSTANCE = "app1"

in model.rb

validates_length_of :name, :within => 3..100, :if => :is_app_one?

def is_app_one?
    APP_INSTANCE == "app1"
end
1

Why not using composition instead of inheritance?

I have a similar issue : an admin app and a public app, with the same database, and only some specific methods on some models for one app or the other.

I'm currently thinking I could create a common place with many modules where I would put my methods. I would then include the modules I need in each app (in models, controllers, helpers, …) when I need them. This place could be in the lib directory (updated with a git submodule or svm external) or in a gem (updated with Bundler or a similar tool).

What do you think about this ?

jlecour
  • 2,905
  • 1
  • 25
  • 24
  • mixins are a form of inheritance. An example of composition would be objects that the main object uses to perform actions, and that are assigned at instantiation or on the fly. – Woahdae Feb 07 '12 at 07:45
1

Just curious - why not have one app with two modes?

I have one application that looks like one of a dozen different apps, branded differently and with different functionality, depending on which URL you're coming in on and who you log in as. My users have roles and I added a method to ActiveRecord::Base that gives you the current user. Thus I can do stuff like:

MAX_VOLUME = current_user.admin? ? 11 : 10
validates_inclusion_of :volume, :in => 0..MAX_VOLUME # Admins can go to 11!

And in the views, stuff like this:

<%= render :partial => common_tabs %>
<%= render :partial => admin_tabs if @current_user.admin? %>
Sarah Mei
  • 18,154
  • 5
  • 45
  • 45
  • 1
    Depends on why they want to seperate out the admin stuff. If it's just for organization, than yeah, your way works... But if it's for security, you could have the two apps running on different sides of a firewall, keep all admin stuff safe from hackers, etc. Just a thought. – J.R. Jun 11 '10 at 13:47
  • You also way want to break it up for memory reasons – say if you're running on Heroku or a shared host. – elsurudo Jun 27 '16 at 13:48