Un-bloating models in rails 3.1 - ruby-on-rails

Just learning rails, developing first app and having trouble finding a straight answer to this question!
I want to keep my models as lean as possible and really only want to use them to represent objects that I might want to render in my views. Therefore, I want to remove some of the logic from one particular model and store it in a separate file. I have seen numerous guides (on this site and others) that suggest the following;
never "require" anything from inside a rails app
Store additional files in the lib folder - they used to be auto loaded in older rails releases but now you need to add an extra line in a config file to get this to happen (Example.
So I added the line, stuck the file in the lib folder, and it all worked fine. So on to the question;
I can't shake the feeling that the fact that I had to go and put some bespoke code into the config file means I'm doing this wrong (given convention over configuration). Why are people having to faff around editing configuration files to get rails to do something so basic?
Is that the best way or are there additional considerations that I'm just not seeing? Should I in fact be creating an "extras" directory rather than still sticking things in lib?
If anyone can point me in the direction of a definitive article on the matter I'd be much obliged!

There is nothing wrong with having non active record models in the model folder. If your domain is best modeled by a business logic layer and a persistence layer, then model it that way in your model folder with appropriate naming conventions. Personally I wouldn't be overly concerned with getting it perfect. Try something and see how you like it.. learn from your mistakes and keep getting better! Above all, enjoy the process.

what I do is this: keep the model logic in the model and keep the controllers as thin as possible
If there are things that should belong to your model but are somewhat distant to it (for example you have an Account model and you're working on some payments system which relates to the Account - for example you might want to call account.has_subscription?, you could use a gem called concerned_with which would split your model's main actions from others like the ones handling payments (this is just an example I recently had to take care of).

Related

Location for "import" code in the rails MVC scheme of directories

Background
We are using these locations as per the Rails standard:
app/models for models (including app/models/concerns to avoid the app/models/*.rb files getting too fat)
app/controllers (including concerns) for lean controllers
app/views as usual
app/view_models for "view models" (Ruby code that is specific to an association between a view and a model, but cannot really exist separately, so cannot really be put into the model or the view)
lib for code that is not calling into app, but is called from app; for things that are really not domain-specific to our application. These are potential candidates for getting extracted into their own gems, if they were to be re-used in other apps.
So far so good, I believe this is all pretty common.
Problem
There is one specific type of code that I am not really sure where to put. This is code related to importing data. This may, for example, be code which processes some XML and does several different actions on the models, but may also be things like code parsing an Excel file, or a class that pulls data from some webservice). Let's see where we could put that:
app/models/concerns - this is where we have that now. But that code is not really representing a model; it is representing a state-changing XML (in this example). It will strongly interact with models, but is not themselves a model; a strong expectation for us is that code in app/models is often used by other classes (i.e., by controllers, views...), but the kind of code we are talking about now is not really doing that.
app/controllers - the part that does any actual file handling and such lives there, this is OK. The processing of the XML data structures does not belong there.
app/views - nope.
lib - nope. The handling of the XML in this example is very domain/app specific.
Question
Where do you put such code? Do you have an app/import subtree? Does it live in the models?
I liked your approach of architecture and folder structure, so couldn't get past your post :)
I think, that app subfolder is definitely the correct place to keep such classes. In our projects we have app/services, app/decorators, app/facades (as an another realization of view_models that we took from Sandi Metz).
Several weeks ago we faced the very same logic, as you and we decided to store it in app/parsers. In your case I would think about app/importers or smth like this.
So my general opinion is that your initial direction is correct for sure.

What are the steps for modifying an existing rails application

I am new to ruby on rails and I am working on a web application written by ruby on rails. It has more than 10 models and I need to add some new attributes to some of the models as well as new methods and views. I also will need to remove or enhance some of the functionality. I know that I would need to generate new migrations and from there add/remove new columns. Then in controllers, add/modify methods, and update the views.
I wanted to know what would be the best steps (and in which order) for doing the above tasks. Also, do I need to change other files in folders like test or any other folder? What things should I consider to minimize the troubles later?
Thanks in Advance.
Since you are new to rails, the first thing you should do is to read through the getting started guide. This will help you understand the fundamentals of the rails framework and the application you inherited. After that, there are several other guides worth reading (from the same site) that may be directly applicable to the work you are doing.
Another incredibly helpful resource is railscasts. Some of these are outdated, but they are still a great starting place and can help introduce you to both new, powerful gems and rails techniques to get the work done faster and better.
As to your specific question, rails is built on an MVC architecture (meaning Model Views Controllers). It is in your best interest to try and follow this practice whenever possible. Reading up on this will clarify some of your questions as well.
When you run a migration, you will be modifying your database. The changes are viewable in the database schema (which should never be modified by hand, always modify it through migrations). This will add attributes to your models whose table you modified. In the controllers, you will add logic to deal with all of these things and the views will present the data to your users (or allow users to enter data). Asking which order is best is probably rather opinion based, but I would say you should modify the tables (run needed migrations) first. This way you can then generate the logic to deal with the new attributes. I would then create the controller logic and finally the views.
You also ask what other files need to be changed. This is heavily dependent on your system. At a base level, you should definitely be writing tests to support the logic you are generating (and many developers will advocate that you should do this before you write the other logic, a process called Test Driven Development).
TL;DR: Read the guides, work through a basic tutorial, and watch some Railscasts. This should get you up to speed on the process and best practices that go along with rails development.

guidelines for where to put classes in Rails apps that don't fit anywhere

I'm wondering if there are any best practices about where to put non-standard Ruby files in Rails apps, those that don't fit in any of the default directories (controllers/models etc.).
I'm talking about classes that are used by controllers/models etc., but are not subclasses of any of the Rails base classes. Classes that include functionality extracted from models to make them less fat. Some of them kind of look like models but aren't AR models, some of them look more like "services", some are something in between or something else.
A few random examples:
"strategy" classes that handle authentication with password, via facebook etc.
"XParams" objects that encapsulate params or "XCreator" objects that handle processing of params to execute some complex action that results in creating some AR models in the end
classes that make requests to external APIs or encapsulate those requests and responses
fake models that can be substituted for a real AR model (e.g. guest user)
Resque jobs
classes that store and read information from Redis
classes that execute some specific actions like processing data, generating reports etc. and are called from Resque jobs or rake tasks
I've got quite a lot of these now, some of them are added to lib which ends up as a pile of random classes and modules, some sneak into app/models. I'd like to organize this somehow, but I don't know where to start.
Should only AR models go into app/models? Or is it ok to also put there any domain or helper models? How you decide if something is a model?
Should everything that doesn't fit into app go into lib? Or maybe I should add a few new custom subdirectories to app? What subdirectories, and how do I divide the custom classes?
How do you handle this in your projects? I know every project is a bit different, but there must be some similarities.
Good question - i don't have a concrete answer for you
but I recommend checking out this post
- http://blog.codeclimate.com/blog/2012/02/07/what-code-goes-in-the-lib-directory/
- be sure to read through all the comments
on a current project i have a ton of non-ActiveRecord objects under app/models, it works but not ideal
i put 're-useable' non application specific code under lib
other alternatives I have tried on side projects (say we have a bunch of command objects)
rails is a pain when it comes to namespaces under app, it loads everything up into the same namespace by default
app/
commands/
products/create_command.rb # Products::CreateCommand
products/update_price_command.rb # Products::UpdatePriceCommand
alternate, everything besides rails under src or an app_name directory
app/
src/
commands/
create_product.rb # Commands::CreateProduct
update_product_price.rb # Commands::UpdateProductPrice
I haven't come across a good solution for this, ideally the 2nd one is better, but would be nice to not have the additional directory under app, that way you open app and see controllers, commands, models etc...
You touch on a number of different use cases, and I think that this part is the closest to the "right" answer:
I've got quite a lot of these now, some of them are added to lib which ends up as a pile of random classes and modules, some sneak into app/models. I'd like to organize this somehow, but I don't know where to start.
That's pretty much right on in my book. The one thing you don't mention is extracting various pieces into separate gems. Classes that talk to external services are excellent candidates for extraction, as are strategy classes if they're sufficiently general. These can be private, since running your own gem server isn't hard, and you can then obviously reuse them across ROR apps.
Last and most concretely, resque jobs I stuff into lib/jobs.
My rule of thumb is if it's a model of some kind, it goes into app/models. If not, it probably belongs in lib or some appropriately named subdirectory thereof, e.g. lib/jobs, lib/extensions, lib/external, or the like.
If you're interested, I also wrote a follow-up article about this a bit later summing up what I found: http://blog.lunarlogic.io/2013/declutter-lib-directory/
I place any model classes (like STI subclasses) in apps/models. I place my other classes in lib, as it seems to be the best place to put them. It's easy for me to know where to look. It's also easier for me to group my tests since my model classes are all in one place.
Convention-wise I'm loathe to put helper classes in app/models. If they're presenter classes they belong in the app/helpers. If they're not then lib seems to be the best place for them.
Often my classes find their way into lib in subdirectories where modules with the same name as the subdirectory is responsible for including them. (Rails is very touchy about filenames and classnames when it comes to the autoloader.)
Another option is to encapsulate each module into its own gem and then refer to the gem via your Gemfile. This permits code sharing across projects.

Modifying Rails: How do advanced users find out what needs to be changed?

I've been using Rails for a few months now, and I'm quite comfortable writing up a project & manipulating Rails to my needs, etc.
Recently I've been trying to get a little more advanced, so I've attempted to modify/add to the existing rails codebase: add new form helper methods, add a responds_to :pdf method, etc...and I've been having a lot of problems.
The difficulty is learning which code I need to modify; where that code is located, and how to ensure I don't miss related code in other files. I'm guessing there's a way people learn to do this, but at the moment I'm mostly just guessing-and-hoping.
I guess my question is, how do Rails folks go about learning where the code they need to modify is edited & the approach to editing it? It seems like it's just something you need to know from prior familiarity, but I'm guessing there has to be a simple method for understanding where (and what) to edit.
Any ideas appreciated...cheers
I highly recommend Jose Valim's Crafting Rails Applications
You go through advanced projects, building out the types of engines and customizations that will take you to the next level in your Rails development.
From the site:
This book will help you understand Rails 3’s inner workings, including
generators, template handlers, internationalization, routing, and
responders.
What you are asking for is how MVC works. Basicly you can say:
1.) Put logic to the model! The model is the pivot everything turns around.
2.) The Controller is a middleman between the model and the view. You dont put any logic here that isnt related to selecting data from the database that should be displayed in the view. If you use one selection logic more than once create a scope in the Model and use it in the Controller.
3.) The View is only there to display things! You dont put any logic here! All the logic comes from the model and the data comes from the controller. The only logic your using here are loops through arrays of data that should be displayed.
Then you have some things missing. If you have a task that is related to an external service like lets say a SOAP Service you write a class for that too! Just whithout using ActiveRecord::Base inheritance like its generated by the scaffolder. You can call this Class in other models. Dont put this to the controller or copy the code in every class that needs it! Stay DRY (Dont Repeat Yourself). Just write a class for it and include it in the other models!
Another thing thats a Database basic: Dont store data that could be calculated from other fields from the database! You can add methods that calculate the stuff you need but dont start with duplicates.

Helpers in rails

I'm just starting out in Rails and there's a lot I still need to learn so I'm likely to be on Stackoverflow more often than normal asking beginner Rails / Ruby questions.
I'm just trying to figure out how Helpers work in Rails. From what I've seen so far, Helpers are intended to be used with Views and not so much with your Controllers.
However I would like to make a simple function that will validate the user input given in params (check if certain params are defined and optionally check if their value is valid).
Can anyone explain to me what would be the best way of implementing this? (Keeping in mind that I will want to use this in many different controllers so it should be globally available.)
I also noticed that by default Rails does not generate a lib folder in the main application folder. Are developers to place their libs outside the app folder in the main folder, or does Rails use libraries differently?
With regards to your validation issue, it depends on what you are validating.
If the data makes up objects from your problem domain, also known as models, then you should use the built in validators from ActiveModel. This is probably what you should do, but its hard to say without knowing the exact problem. See the Rails Guides on Validations. You can tell if this is the case by asking yourself if the data that needs validation will be stored after you get it. If so, its most definitely a model. An example of this kind of data would be the title and text fields of a blog post being sent to Rails from a browser form.
If the data is something tertiary to your models, or specific to presentation, then you should be fine using helpers. You noticed that helpers are used mostly in the views, and although this is true, theres nothing stopping you from using them in the controllers, you just have to declare that you will use them using the ActiveController#helper method. Inside the ApplicationController class, a lot of devs will put helper :all to just include all the helpers in all the controllers. Once the code has been required once, it doesn't really incur that big a performance hit.
Do note that almost all incoming data can be modeled using a model. A big school of thought in the Rails world subscribes to the Fat Model idea. People say that putting as much code as possible in the model and as little in the controller as possible separates concerns properly and leads to more maintainable code. This suggests that even if you don't think the incoming data is modelable (in the sense that you can create a model to represent it), you should try to make it a model and encapsulate the logic around validating it. However, you may find that making a helper function is faster, and either will work.
Your notion of validating user input is a good one. I get the feeling that as you are new to Rails you are used to doing these things yourself, but that doesn't quite apply here. In the Rails world, a lot of the common stuff like validations is handled by the framework. You don't have to check for presence in the params array, instead you call validates_presence_of on the model and let Rails spit the error out to the user. It makes things easier in the long run if you let the framework do what it is designed to.
With regards to your question about the lib folder, it doesn't really matter. You can put miscellaneous support files and libraries in the lib folder in the root directory and they will be available for use in your application (the files in the app folder). You can also choose to abstract your code into a plugin or a gem and include it that way, which a lot of people opt to do. My suggestion for this would be to read up on the notion of gems and plugins before diving in.
Want you want is probably a custom validator (in Rails3):
http://railscasts.com/episodes/211-validations-in-rails-3
You can either add libs in a lib folder you create, or add them to config/initializers in a file you add. Files in the initializers directory are automatically loaded by Rails.

Resources