How to handle similar items in rails MVC? - ruby-on-rails

I'm working on building a pretty simple site mainly as an exercise in
learning more about rails. You can see my rough progress at
statific.com. It's working pretty much as I wanted it for
keeping track of server information, but now I'd like to expand it to
other things, next on the list being firewalls.
I can pretty easily duplicate all the models, views, etc.. that I have
for my servers. The problem I see with that is that it isn't very DRY
since most of the code would look the same, the only difference would
be the attributes I have setup for firewalls would be different than
for servers.
I know in plain ruby this is pretty simple, you can have a 'Product'
w/ common attributes ('manufacturer', 'model') and then have children
with more specific attributes. Does the same type of concept exist
for rails, or am I just over thinking this?

Use STI (please don't poke me to death. I'm just kidding).
All common functionality should be moved to modules and included into different models (server, firewall, etc.) as needed. In this particular situation you could have a module Hardwareable and include it into your server and firewall models. And leave different attribute to appropriate models.

Related

Deciding between using an array attribute or a nested model

Possibly a fairly basic question, but bear with me.
I'm building a page which has a number of pieces of modular content, represented by a ContentBlock model. Each ContentBlock has at least one link, each of which has a couple of different attributes. My initial approach was to just add these links as an array to the model, as there didn't seem to be any real need to store them separately in the database, and they don't have any logic of their own. Now that I'm looking at building a form for creating/editing a ContentBlock though, it seems like it would be much easier to build if there was a separate, nested model for the links.
I'm strongly considering converting to using a model, but my gut feeling is that it's kind of "wrong" to store something like as relatively trivial as the links are in the DB. Given I am still getting used to working with Rails, is this feeling misplaced? Should I just create models for anything and everything? Or should I be looking for some sort of minimum criteria before I do?
It is definitely easier to create forms for nested models. Since your links have attributes, I'd suggest making a model. I tend to err on the side of making models for concepts that can't easily fit into fields. If you're worried about query performance, you can always do eager loading.
I think depends on how much data you plan on managing, what you want to do against that data, what that data represents, etc...
One project we had was to build something that allowed creation of recipes for a group of restaurants. Recipe (some text, like instructions, etc...) -> Ingredient, we went with an array, as these were all single lined text and there would never be more than several hand fulls. Also, the ingredients had no further dependencies. The Recipes would only be rendered out to html and there would be no searching against them (not against the db at least).
Another project required building a Page, very similar to yours, but each "component" of the page did different things and some where linked to other objects in the app, like Videos and other assets, templates, etc... We had seen people do this type of stuff entire through a wysiwyg or through some JS way and saved the entire payload/structure in the DB. We found both to be extremely messy.
And one concern that came up was what happened if an asset/associated object was mistakenly or purposely deleted but lived throughout many pages. Using models allowed to ensure that if something got removed, it got removed within all it's linked associations (though this posed problems of it's own, but more regarding the page making sense when displayed more than anything else).
Also, our Page had the potential of becoming extremely large with different types of components with different looks and inter-activities, that this really was the only way we could properly manage it.
So I would look at your requirements and plan accordingly, context matters. And if you have to change it (which happens, a lot) then you'll change it.

Namespacing models in a Rails application

I had a discussion recently with a friend of mine who is also a RoR developer. We argued about how Rails models should be managed. Personally I like to leave in the default namespace only the root models (e.g. User, Article, Bill etc.), and the dependent models go to a module (e.g. User::Profile, User::Activity) with the name of the root model they are associated with.
On the other hand, I've seen many projects which had like 100 models in the default namespace called like user_profile, user_activity and so on. Judging by Java (Spring) development, java community tends to organize class in packages and have them grouped logically, which I find very appealing.
So the question is: are there any drawback in grouping models in modules (except the extra :class_name in relation definition) and are there any specific reasons why people usually don't do it?
Although namespacing has its advantages, it does require adding exceptions throughout your models. Foo::Bar presumes a table name of bars and likewise bar_id for associations, whereas you might prefer foo_bars and foo_bar_id to be used instead.
If you really feel strongly about this, you might want to see if there's an add-on that fixes this for you, or implement your own extension that does.
The only case when I've used namespaces is for add-ons that are to be used in third party applications where I don't want to claim root-level model names as that would be annoying. The extra effort in this case is worth-while.
If you're bothered by seeing 100+ model files without any grouping, you'll probably be equally annoyed by seeing 100+ tables with no grouping, and that's generally something you can't fix.
Controllers lend themselves to grouping quite naturally, but models aren't as easily accommodated, at least not with stock ActiveRecord.

Building consumable uri/urls for a model (rails/datamapper/SOA)

Perhaps you can help me think this through to greater detail.
I need to build or make available a uri for a model instance that can be referenced or used by another application which may or may not be a rails application.
e.g.
I create a standard Post with content; I want to build a URL for that post another application can consume or reference by looking at the model in the database (or another less sticky fashion). Datamapper has a URI field, I want to build a canonical uri, store it there and have another application be able to access, announce, manipulate, etc.
Basically, I have several applications that may be in different places, that need to access the same model, to do differing things with the model. I need a way to make that happen clearly without putting them all in one monster application.
I've looked at Pubsubhub, RSS, etc. but haven't found any concrete examples of what I'm trying to do. Do I need to create an common API for the applications, etc?
DataMapper is very flexible about using existing databases.
Many people come to DataMapper because it can create and tear down the database structures without migrations. However, you do not have to work with it in that way.
I have had good success with using a large set of models owned by a central 'housekeeping' app and then declaring a small subset of the same models in separate 'interface' apps.
Some trial and error is required to figure out what works but it can certainly be done. I'd suggest putting your models in modules and including them across apps if possible.
A final point it sounds like you want URIs/URLs to be the primary interface. If that is the case I strongly suggest you look at Sinatra. It is entirely oriented around URLs (and I find Rails routes very obtuse).

Rails Basecamp style subdomains best practice

My goal is to have separate user accounts for each subdomain. Under no circumstance do I want cross-pollination between subdomains.
I've looked over Robby Russle, and DHH's thoughts (both are pre-Rails3 though).
The controller handling is pretty straight forward, my questions is about keeping the model's data separated. What's the best way to keep user1 from seeing user2's data?
Some idea's might include:
Add a subdomain_id foreign key to every model - Advantage, simple one-to-many relationship can be used to scope each model to a subdomain. - Disadvantage, this is pretty tight coupling between the data and the larger application logic, which seems inappropriate.
One-to-many :through for each model associating it with a subdomain - Advantage, no need to add a subdomain_id foreign key column to existing tables associating them with their sub domain. - Disadvantage, My gut feeling is that this is way overkill. Multiple join queries may get complicated and cross-pollination bugs may occur.
Separate applications or databases for each subdomain - Advantage, the data is completely segregated. - Disadvantage, a large number of individual applications/databases will need to be managed/updated/secured/hosted/etc.
Your idea?
Option 5. Guy Naor's Schema solution - Advantage, This just blew my mind. Mostly transparent to rails, COMPLETE data separation, only one database, works really great for applications that weren't originally designed as multi-tenant. a-mazing. - Disadvantage, need to be using Postgres, or some other database that supports schemas (I'm already using PG anyway), you'll need to iterate over existing schemas when you migrate.
Right now this seems far and away the best way. Are there any major drawbacks?.
If you're sure the object-to-subdomain relation will always be one-to-one, I would pick option 1. If objects might be related to multiple subdomains in the future you're bound to option 2. It incurs more overhead, but it's easily managed when using something like cancan.
I would stay away from option 3 for the reasons you mentioned. Rails doesn't do multiple databases well and besides, using multiple databases in one application doesn't guarantee any more security than the other options.

What is the best strategy to combine IntrAnet and Web-exposed website?

I was wondering if somebody has some insight on this issue.
A little background:
We've been using Rails to migrate from an old dBase and Visual Basic based system
to build internal company IntrAnet that does things like label printing,
invetory control, shipping, etc - basically an ERP
The Dilemma
Right now we need to replace an old customer-facing website that was done in Java, that
would connect to our internal system for our clients to use. We want to be able to pull information like inventory, order placement, account statements from our internal system and expose it to site live. The reason is that we take orders on the website, through fax & phone and sometimes we have walk-ins. So sometimes (very rarely thou) even a short delay in inventory update on our old Java site causes us to put an order on backorder, because we sell the same item to 2 customers within half an hour. It's usually fixed within one day but we want to avoid this in the future.
Actual Question
Does anyone have any suggestion on how to accomplish this in a better
way?
Here are three options that I see:
a) Build a separate Rails app on a web server, that will connect to the same DB that our internal app connects to.
+++ Pluses:Live data - same thing that our internal apps see, i.e. orders are created in real time, inventory is depleted right away
--- Minuses: Potential security risk, duplication of code - i.e. I need to duplicate all the controllers, models, views, etc. that deal with orders.
b) Build a separate Rails app on a web server, that will connect to a different DB from our internal app.
+++ Pluses: Less security exposure.
--- Minuses:Extra effort to sync web DB and internal DB (or using a web service like REST-API), extra code to handle inventory depletion and order # creation, duplication of code - i.e. I need to duplicate all the controllers, models, views, etc. that deal with orders.
c) Expose internal app to the web
+++ Pluses: all the problems from above eliminated. This is much "DRY"er method.
--- Minuses: A lot more security headaches. More complicated login systems - one for web & one for internal users using LDAP.
So any thoughts? Anyone had similar problem to solve? Please keep in mind that our company has limited resources - namely one developer that is dedicated to this. So this has to be one of those "right" and "smart" solutions, not "throw money/people/resources at this" solutions.
Thank you.
I would probably create separate controllers for the public site and use ActiveResource to pull data from you internal application. Take a look at
http://blog.rubybestpractices.com/posts/gregory/rails_modularity_1.html
http://api.rubyonrails.org/classes/ActiveResource/Base.html
Edit - fixed link and added api link
I would go for a. You should be able to create the controllers so that they are re-usable.
Internal users are as likely to duplicate data as external users.
It's likely that a public UI and an internal, for-the-staff, UI will need to be different. The data needs to be consistent so I would put quite a bit of effort into ensuring that there is exactly one, definitive database. So: one database two UIs?
Have a "service" layer that both UIs can use. If this was Java I would be pretty confident of getting the services done quickly. I wonder how easy it is in Ruby/Rails.
The best outcome would be that your existing Customer Java UI can be adapted to use the Rails service layer.
Assuming you trust your programmers to not accidentally expose things in the wrong place, the 'right' solution seems to me to have a single application, but two different sets of controllers and views, one for internal use, and one for public-facing. This will give you djna's idea of one database, two UIs.
As you say having two separate databases is going to involve a lot of duplication, as well as the problem of replication.
It doesn't make sense to me to have two totally separate apps using the same database; the ActiveRecord part of a Rails app is an abstraction of the database in Ruby code, therefore having two abstractions for a single database seems a bit wrong.
You can also then have common business rules in your models, to avoid code duplication across the two versions of the site.
If you don't completely trust your programmers, then Mike's ActiveResource approach is pretty good - it would make it a lot harder to expose things by accident (although ActiveResource is a lot less flexible and feature rich than ActiveRecord)
What version of Rails are you using? Since version 2.3 Rails Engines is included, this allows to share common code (models/views/controllers) in a Rails plugin.
See the Railscast for a short introduction.
I use it too. I have developed three applications for different clients, but with all the shared code in a plugin.

Resources