Newbie on Rails

Hello everyone.

Near the end of last week I've decided to get my hands on a project that, unfortunately, has been lying around in my desk for a while now.

As with any other project I've elaborated my project plan, with all the requirements, risks, issues, resources, etc. After that, I started my quest to figure out which would be the best set of technologies for this particular project.

This was when I became acquainted with Rails. I've heard about it before, but never had the time to dig into it and check what exactly it was.

On a first look Ruby seems like a weird language, after so many years of programming in both PHP and Microsoft .Net's C#, for web and desktop. But, that should not be a problem. It's a question of time. However, after reading and exploring Ruby on Rails I found a couple of issues that got me worried enough to post this message, on Ruby-Forum.com. These are:

- Over the time I've started developing websites using a set of design patterns and practices. For instance, I always develop one or more APIs, containing the business logic, which is implemented in all interfaces preventing me from duplicating all the business logic. Also,

- I've noticed that Ruby on Rails imposes the MVC paradigm, which is good. But, as a newbie when it comes to real use of MVC, it seems like a limitation as I usually go for fine-grained URLS. For example, consider the following URL for the sample domain MySite.com: http://www.mysite.com/supplier/management/permissions/ My clients came to love this kind of URLs. It let's them know exactly where they are, without weird names. But how could this be implemented under the MVC paradigm? All the code would have to be under the supplier controller? What if there are 100 things to manage, as a supplier, with [say] 60 interfaces? Will all that code have to be in the supplier controller and model?

How could I implement something like I've always done in MVC? How can I overcome my API problem?

All suggestions are welcomed. Best regards.

Diogo Delgado wrote:

These are:

- Over the time I've started developing websites using a set of design patterns and practices. For instance, I always develop one or more APIs, containing the business logic, which is implemented in all interfaces preventing me from duplicating all the business logic. Also,

That is what MVC is all about. All the business logic for an object is contained in the models, the controllers orchestrate the interactions between the models and pass the results to the view.

- I've noticed that Ruby on Rails imposes the MVC paradigm, which is good. But, as a newbie when it comes to real use of MVC, it seems like a limitation as I usually go for fine-grained URLS. For example, consider the following URL for the sample domain MySite.com: http://www.mysite.com/supplier/management/permissions/ My clients came to love this kind of URLs. It let's them know exactly where they are, without weird names. But how could this be implemented under the MVC paradigm?

Check out the config/routes.rb file - this is where these URLs are defined.

All the code would have to be under the supplier controller? What if there are 100 things to manage, as a supplier, with [say] 60 interfaces?

Nested routes are your answer.

Will all that code have to be in the supplier controller and model?

How could I implement something like I've always done in MVC? How can I overcome my API problem?

I assume your "API problem" is limited to the URLs (for you not mentioned anything else), but you might want to checkout RESTful resources which will enable a complete REST interface for free.

Andrew Skegg wrote:

That is what MVC is all about. All the business logic for an object is contained in the models, the controllers orchestrate the interactions between the models and pass the results to the view.

Yes, but I rather have my business logic in an API than in a model. This is because I just don't know when I'll need to reuse it.

It would be like developing an ASP.net all in one project. That's rather suicidal, from an application scalability / reusability point of view.

Check out the config/routes.rb file - this is where these URLs are defined.

I've seen this file, but I haven't tryed to "hammer" it just yet :wink:

Nested routes are your answer.

I'll take a look at that. Could you advance me on how would it work for my sample URL (http://www.mysite.com/supplier/management/permissions/)?

I would need a route for the /{controller} with a nested route for the /{controller}/{sub-module / sub-controller}/{action}, which in turn would point to a controller file called, for example, supplier_management_permissions_controller.rb?

I assume your "API problem" is limited to the URLs (for you not mentioned anything else), but you might want to checkout RESTful resources which will enable a complete REST interface for free.

That's one way to solve it. I could have an app with REST services, and another app consuming it. However, I'm yet to determine if the overhead would be something that I'm interested just yet. Perhaps developing a library, written in Ruby, and consumed by the Ruby on Rails app would be another way to do it. However, I suppose that the lib would miss all the RoR fun :wink:

Diogo Delgado wrote:

I'll take a look at that. Could you advance me on how would it work for my sample URL (http://www.mysite.com/supplier/management/permissions/)?

I would need a route for the /{controller} with a nested route for the /{controller}/{sub-module / sub-controller}/{action}, which in turn would point to a controller file called, for example, supplier_management_permissions_controller.rb?

You seem to have three models operating here - suppliers, management, and permissions. These might look like the following:

class Supplier < Activerecord::Base end

class Management < Activerecord::Base   has_many :permissions end

class Permission < Activerecord::Base   belong_to :management end

Although, you might want to subclass Management from another model, say Users?

The routes then might look like this:

map.resources :suppliers do |supplier|   supplier.resources :management do |manager|     manager.resources ;permissions   end end

or something like:

map.resources :suppilers, :has_many => :managers map.resources :managers, :has_many => :permissions

(untested and you may want to fiddle with the code to get the routes you are looking for).

Run "rake routes" at the terminal to get a list of the routes table.

I assume your "API problem" is limited to the URLs (for you not mentioned anything else), but you might want to checkout RESTful resources which will enable a complete REST interface for free.

That's one way to solve it. I could have an app with REST services, and another app consuming it. However, I'm yet to determine if the overhead would be something that I'm interested just yet. Perhaps developing a library, written in Ruby, and consumed by the Ruby on Rails app would be another way to do it. However, I suppose that the lib would miss all the RoR fun :wink:

Sticking to the 7 methods in the controllers for each model and hooking them together with routes will give you all you need. Although, depending on your requirements, you may need to create one REST application that services others.

Andrew

Andrew Skegg wrote: > That is what MVC is all about. All the business logic for an object is > contained in the models, the controllers orchestrate the interactions > between the models and pass the results to the view.

Yes, but I rather have my business logic in an API than in a model. This is because I just don't know when I'll need to reuse it.

That got me stumped a bit when I started (and I am still starting) the learning process with RoR. However, I realized that even with a "man in the middle" interface, such as the old "file from the mainframe uploaded to a website" interaction - business logic can still be contained in my model, even if I am simply modeling a file, not a database. It's as if you decide how big the fields need to be (fixed length), or how one database value requires a certain set of characters, in a container that "wraps" itself around the eventual output. It has worked really well so far, especially in making me think in the idea of containers and such.

Also, if I know I have a model called "BankCoUpload" (or whatever) - I know that, from anywhere else, I can stuff data through that model/ controller and meet whatever spec was created for that purpose.

@Diogo: I think you'll need to be more specific about what you mean by the "API problem" before you can get really helpful comments on that.

Ruby does not have the same type of interfaces that you've come to rely on C# and similar languages. It's much more reliant on duck- typing and, used effectively, you can achieve a similar result. Specifically, you don't worry about whether or not a class implements a specific interface; from a duck-typing/Ruby perspective you _really_ want to know if it performs some method. And if that's your objective, you just ask it:

an_instance.respond_to?(:some_interesting_thing_to_do)

You can then move on gracefully if your object does not respond to the method in question or raise an exception if you prefer exception handling for that type of thing.

You will also want to look into using 'modules'. Modules fall somewhere between interfaces and abstract classes on the C# scale. They allow you to craft a specific interface, interact with private state of the class, but do so at a completely abstract level. For example, in one application I've built I have things like addresses and phone numbers and the like that are valid for a particular date range. I needed to allow the user to say 'replace the home address/ phone with X value starting on Y date'. To handle that I wrote a module that dealt only with the activation and deactivation dates and provided a simple api for asking whether the instance that I found was the currently active on, or to find the one that was active on a specific date. It also enforced the rules about preventing two objects from being active at the same time. What was nice was that the module gave me the api (interface) but I could program it with real instance/state information (abstract class) but without caring what class I was dealing with or imposing a requirement that the classes themselves implement the method (interface).

The MVC framework may not be a huge help to you if you've been a particularly disciplined OO developer. Unfortunately I've done enough project where I was always perfectly disciplined and everyone else messed things up. :slight_smile: MVC is a good guide for everyone because it _helps_ enforce proper separation. It's the same type of n-tiered solution that .net developers always want until the drag-and-droppers get involved.

As for the URL issue, there are several ways to get to the kinds of urls that you want. In fact, one of the reasons that many people like rails is for the same kind of clean urls that you've apparently been using. There are a few things that will be helpful for you to achieve those urls. First, you can use namespacing. This is similar to what you'd do in .net in that it allows you to segment the application and group similar concerns within the overall solution. What's as nice (or better) is that the organizational principle gets reflected in the url as well. That is, all of your admin or management views would be grouped together in the project AND the url would include /admin or / management as you've described.

The default routing, particularly nested routing, would help you go even further. By convention, rails generates routes that follow a format of

collection_name/[token]

Which is to say all your customers could be retrieved by hitting / customers, but a specific customer would be found by hitting / customers/1234 (where, by convention, 1234 is the id of the customer). One of the nice things that you can do, though, is to override a method specifically used by the routing so that your url instead looks like

/customers/pragmatic_programmers

where pragmatic_programmers is the name of the customer, downcased and with underscores added. Your customers might like that even more since they could bookmark 'frequent flyers'.

Nested routes are similar. The 'nesting' comes in the fact that you'd get /parent_collection/[parent_token]/child_collection[token]. The format can be really handy when you're adding a new item to a child collection because the identifier is passed along to the controller that handles the children.

It's also worth noting that you can completely bypass the RESTful routing if you want. The routes.rb file permits several ways to add a url to the route map so you can continue to use the same kinds of urls that you are using today. In short you give the route a name, describe it's pattern (perhaps with a string), and then tell it what controller and action (method) should respond. The routing system even permits regex matching, making it easy to provide, for example, dated blog entries that conform to something like /posts/2008/may.

As a reformed C# guy myself I can say that I never look back and wish I had the 'opportunity' to select just the right collection of objects and configurations from among the 25K+ that MS has to offer. In fact, I'm thankful every day that I hooked up my friend to do contract work on a legacy project so I can stay .net free for yet another day!

Feel free to contact me off line if you want to talk any more specifics.

AndyV, first of all, thanks for your enlightning reply.

Back to the topic, let me reply to your post by splitting it in smaller quotes.

AndyV wrote:

@Diogo: I think you'll need to be more specific about what you mean by the "API problem" before you can get really helpful comments on that.

Ruby does not have the same type of interfaces that you've come to rely on C# and similar languages. It's much more reliant on duck- typing and, used effectively, you can achieve a similar result. Specifically, you don't worry about whether or not a class implements a specific interface; from a duck-typing/Ruby perspective you _really_ want to know if it performs some method. And if that's your objective, you just ask it:

an_instance.respond_to?(:some_interesting_thing_to_do)

You can then move on gracefully if your object does not respond to the method in question or raise an exception if you prefer exception handling for that type of thing.

Yes, I could do that. It just feels strange that there's no real contract enforced by design, only at runtime by the "host / invoker". In practice it boils down to a matter of principles and vicious programming styles, where you apply the same design patterns over and over, throughout the countless projects.

You will also want to look into using 'modules'. Modules fall somewhere between interfaces and abstract classes on the C# scale. They allow you to craft a specific interface, interact with private state of the class, but do so at a completely abstract level. For example, in one application I've built I have things like addresses and phone numbers and the like that are valid for a particular date range. I needed to allow the user to say 'replace the home address/ phone with X value starting on Y date'. To handle that I wrote a module that dealt only with the activation and deactivation dates and provided a simple api for asking whether the instance that I found was the currently active on, or to find the one that was active on a specific date. It also enforced the rules about preventing two objects from being active at the same time. What was nice was that the module gave me the api (interface) but I could program it with real instance/state information (abstract class) but without caring what class I was dealing with or imposing a requirement that the classes themselves implement the method (interface).

I see.

The MVC framework may not be a huge help to you if you've been a particularly disciplined OO developer. Unfortunately I've done enough project where I was always perfectly disciplined and everyone else messed things up. :slight_smile: MVC is a good guide for everyone because it _helps_ enforce proper separation. It's the same type of n-tiered solution that .net developers always want until the drag-and-droppers get involved.

Not a huge help at all... I'm a MVC beginner. Therefore, I can only hope that what I now consider to be a feature that complicates what was simple will become a plus over time. Hard to forsee such future, just yet :slight_smile:

As for the URL issue, there are several ways to get to the kinds of urls that you want. In fact, one of the reasons that many people like rails is for the same kind of clean urls that you've apparently been using. There are a few things that will be helpful for you to achieve those urls. First, you can use namespacing. This is similar to what you'd do in .net in that it allows you to segment the application and group similar concerns within the overall solution. What's as nice (or better) is that the organizational principle gets reflected in the url as well. That is, all of your admin or management views would be grouped together in the project AND the url would include /admin or / management as you've described.

Sounds like a very interesting and promissing thing. Will have to dig into that.

The default routing, particularly nested routing, would help you go even further. By convention, rails generates routes that follow a format of

collection_name/[token]

Which is to say all your customers could be retrieved by hitting / customers, but a specific customer would be found by hitting / customers/1234 (where, by convention, 1234 is the id of the customer). One of the nice things that you can do, though, is to override a method specifically used by the routing so that your url instead looks like

/customers/pragmatic_programmers

where pragmatic_programmers is the name of the customer, downcased and with underscores added. Your customers might like that even more since they could bookmark 'frequent flyers'.

Nested routes are similar. The 'nesting' comes in the fact that you'd get /parent_collection/[parent_token]/child_collection[token]. The format can be really handy when you're adding a new item to a child collection because the identifier is passed along to the controller that handles the children.

It's also worth noting that you can completely bypass the RESTful routing if you want. The routes.rb file permits several ways to add a url to the route map so you can continue to use the same kinds of urls that you are using today. In short you give the route a name, describe it's pattern (perhaps with a string), and then tell it what controller and action (method) should respond. The routing system even permits regex matching, making it easy to provide, for example, dated blog entries that conform to something like /posts/2008/may.

Yes, it's somewhat familiar with the ASP.net 3.5 extensions MVC framework routing.

As a reformed C# guy myself I can say that I never look back and wish I had the 'opportunity' to select just the right collection of objects and configurations from among the 25K+ that MS has to offer. In fact, I'm thankful every day that I hooked up my friend to do contract work on a legacy project so I can stay .net free for yet another day!

When I saw Rails, and started reading more about it, I've considering dropping .net all together. Well, for the web at least. Only the test of time will tell how fast I apply the same, or adjusted patterns, to rails and if that makes me save money or waste money.

Feel free to contact me off line if you want to talk any more specifics.

Could you send me and e-mail and / or MSN to ahkaru [at] gmail [dot] com ? Would be interesting to discuss a couple of points with you.

Best regards and thanks again.