I am a beginner to RoR and could use some guidance. I have been trolling this stackoverflow answer religiously these past few days.
Rails engines extending functionality
But the error that keeps being thrown is: 'undefined method join'
I have an abstract model called OrderError. OrderErrorDetails is my other model , which is used to actually store data within the database. The OrderError abstract model is here solely to provide functionality, not to store anything. :
module MyEngine
class OrderError
self.abstract_class = true
has_one :order_error_detail
def self.new
#my_code
end
end
end
So what I tried instead of requiring (stack overflow link above) was placing the following code to my app's Order Model:
order_error MyEngine::OrderError.new
When I did this, I was able to successfully access my engines OrderError model. However, the error I now get is: The method .order() must contain arguments.
My hope is that once the engine is mounted into an app, I can call my engines various methods. This will provide the user of the engine some default functionality.
Should I be using abstract classes to begin with? In my mind the answer is yes, because my abstract model's only purpose is to provide methods that can be used. If so, how does one efficiently provide access to those methods?
using:
MyEngine::OrderError.new
is the correct way to extend engine model functionality. In the above example, the method "new" had some problems with the way it was structured. This comes down to engine namespacing. Every class is encapsulated in the module of MyEngine (The engine name). This is so that your engine code is modular and seperate from its parent app code. The best explanation for namespacing was found on the getting started with engines guide here: http://guides.rubyonrails.org/v3.2.13/engines.html#what-are-engines
Related
I am a newbie in Ruby on Rails. Coming from a C# and Java background, Ruby on Rails seems bizzare, yet interesting at the same time. It's almost like coming from a class-based object-oriented world to the prototyping concept of JavaScript, or even to a functional language.
Anyways, in a traditional C# or Java MVC application, I tend to keep my models and controllers as clean as possible, extracting the business logic into service classes. My models are just POCOs/POJOs (with some calculated fields and validation at most). And my controllers just process incoming requests (relying heavily on dependency injection) and then return a view or JSON.
Yet, I do not see any clear pattern in the RoR world. Some people tend to put all their business logic into controllers, some put it into models (with ActiveRecords, it kind of makes sense, although I don't like it).
And then there is the concept of Concerns. Are they the right place to extract my business logic, instead of using services? If yes, could you include an example of proper Concers use? I still struggle with the concept of modules (are they more of namespaces, or rather interfaces)? As said at the beginning, Ruby seems like a whole new galaxy to me.
This question could get into the weeds a bit as it brings in a lot of personal preferences. However here is my take on it.
First, Concerns are not a replacement for Service classes. Concerns are a clean and nifty way to manage your mix-ins. If you are new to Ruby, mix-ins are basically a way of injecting instance and/or class methods into existing classes. For example, given these classes:
class EvilRobot < ActiveRecord::Base
def destroy(target)
...
end
end
class OrneryTeenAger < ActiveRecord::Base
def destroy(target)
...
end
end
you could dry out the code with:
require 'active_support/concern'
module EvilTools
extend ActiveSupport::Concern
included do
def destroy(target)
...
end
end
end
class EvilRobot < ActiveRecord::Base
include EvilTools
end
class OrneryTeenAger < ActiveRecord::Base
include EvilTools
end
I think that the vast majority of Rails developers, myself included, go for a fat-model, thin controller design. Just how fat though is a matter of taste. I also tend to move functionality to classes under lib if they don't fit logically within a model, or extract into an engine or gem.
I would say jpgeek reaction is part of the answer. The is a lot of movement towards service objects to clean up fat models or large controllers actions. Just create an app/services folder and create service classes like:
class TargetDestructionService
def initialize(shooter, target)
#shooter = shooter
#target = target
end
def execute
#Lot of code that causes the destruction of the target.
end
end
Then in your model or controller you would call:
TargetDestructionService.new(EvilRobot.new, Human.new).execute
Here is a nice article about it: https://blog.engineyard.com/2014/keeping-your-rails-controllers-dry-with-services
In the Rails application I’m currently developing I have many “request” models. We are using a lot of web services and we have a lot of different requests to those services, each of them with their own logic (mostly validations). So they are all grouped in a module as a namespace:
module Request
end
So now every request is something like:
class Request::SendSomeData
end
So far, so good… The thing is that we are going to have a lot of such requests which will share some common logic. It is easy to include the module
class Request::SendSomeData
include Request
end
… (so it will act both as a namespace and a mixin), but I was wondering if there is a way to make it without the include (as it is going to be some kind of code repetition).
Is there a way for Ruby to put some instance methods to all the classes in a module’s namespace without explicitly including the module?
In other words can I have something like:
module Request
def someMethod
end
end
and
class Request::SendSomeData
end
and be able to use
Request::SendSomeData.new.someMethod
at the same time?
What you are asking can't be done without some evil hackery.
You either have too many classes, or are focusing on an issue that is too unimportant. It's only one line of code per class.
An alternative is to create a base model class, as I have previously described in another question, but this requires the derived classes to each call set_table_name, so it won't save you any typing.
I have a Rails app with a few model classes (e.g. Category, Subcategory, User, etc.). In order to implement a not-too-trivial filter functionality, I built a hierarchy of filter classes: FilterCategory, FilterSubcategory, etc., that derive from FilterBase. Each of them uses the appropriate "sister" model class (e.g. Category.find :all).
I quickly realized that I can't simply call the "sister" model class without using "require" first. However, I now suspect that using "require" is the main reason for two other problems I posted here and here, which probably mess up the class caching when config.cache_classes=false.
Is there another way for me to call these other models without requiring them?
I tried using the BaseWithoutTable plugin, but when I call the "sister model", I end up getting "Not a valid constant descriptor: nil", which occurs since Rails looks for "FilterCategory::Category" rather than "Category".
Any thoughts of the best way to do that?
I'm using Rails 2.3.8, Ruby 1.8.7.
Thanks,
Amit
I wonder if you want ::Category - getting Category from the top-level namespace rather than scoping it to FilterCategory?
If your models are in the app/models directory, you shouldn't need to explicitly require them - Rails already takes care of that.
I'm working on a project where the data model is :
implemented in a separate gem
does not use ActiveRecord, nor any relational database storage ( actually it relies on couchdb )
makes usage of namespaces
makes intensive usage of class inheritance
To simplify the schema, let's say we have the following root class :
module Marketplace
module Food
class Fruit
…
end
end
end
And a couple of specialized classes :
module Marketplace
module Food
class Peach < Marketplace::Food::Fruit
…
end
class Tomato < Marketplace::Food::Fruit
…
end
end
end
I'd like Rails to display (and manage) all the Fruits whatever is their nature, without modifying the model witch works perfectly out of Rails.
The issue is that ActionView seems to use a certain number of conventions for defining paths and urls that will be based on the real class names.
So if I present an Apple, in a table with show/delete actions, rails will look for a methods named marketplace_food_apple_path and similar which of course don't exist.
Is there a way to indicate the ActionView::Base structure(s) that an Apple is a Fruit ?
I'd expect this 'base cast' to be 'trivial' for a framework based on Ruby but it seems that this simple example of object oriented model does not work with Rails ?
How do you manage 'complex object' data models in rails ?
Or it is simply out of scope of Rails ?
Thanks for any pointers !
http://railstips.org/blog/archives/2009/05/15/include-vs-extend-in-ruby/ <-- probably what you want, unless you're just looking to argue the single inheritance versus multiple inheritance strawman.
OK as I see there are plenty of useful answers ;).
It basically confirms my doubts on Rails which I see more like a sort of VB : easy to learn, nice for small things (shopping or community sites) but very limited.
Rails is completely out of scope when it gets to handling complex business logic and data !
As Rails 3.0 does not seem to be the answer neither (ok we have several ORM's but we're still unable to use inheritance in the model) I switched to Ramaze, a small framework that makes no assumptions on how the data is organized making it suitable for almost any kind of web needs.
If you are facing model constraints with Rails, maybe you should forget about Rails and check Ramaze !
I'm really enjoying Rails (even though I'm generally RESTless), and I enjoy Ruby being very OO. Still, the tendency to make huge ActiveRecord subclasses and huge controllers is quite natural (even if you do use a controller per resource). If you were to create deeper object worlds, where would you put the classes (and modules, I suppose)? I'm asking about views (in the Helpers themselves?), controllers and models.
Lib is okay, and I've found some solutions to get it to reload in a dev environment, but I'd like to know if there's a better way to do this stuff. I'm really just concerned about classes growing too large. Also, what about Engines and how do they fit in?
Because Rails provides structure in terms of MVC, it's natural to end up using only the model, view, and controller containers that are provided for you. The typical idiom for beginners (and even some intermediate programmers) is to cram all logic in the app into the model (database class), controller, or view.
At some point, someone points out the "fat-model, skinny-controller" paradigm, and intermediate developers hastily excise everything from their controllers and throw it into the model, which starts to become a new trash can for application logic.
Skinny controllers are, in fact, a good idea, but the corollary--putting everything in the model, isn't really the best plan.
In Ruby, you have a couple of good options for making things more modular. A fairly popular answer is to just use modules (usually stashed in lib) that hold groups of methods, and then include the modules into the appropriate classes. This helps in cases where you have categories of functionality that you wish to reuse in multiple classes, but where the functionality is still notionally attached to the classes.
Remember, when you include a module into a class, the methods become instance methods of the class, so you still end up with a class containing a ton of methods, they're just organized nicely into multiple files.
This solution can work well in some cases--in other cases, you're going to want to think about using classes in your code that are not models, views or controllers.
A good way to think about it is the "single responsibility principle," which says that a class should be responsible for a single (or small number) of things. Your models are responsible for persisting data from your application to the database. Your controllers are responsible for receiving a request and returning a viable response.
If you have concepts that don't fit neatly into those boxes (persistence, request/response management), you probably want to think about how you would model the idea in question. You can store non-model classes in app/classes, or anywhere else, and add that directory to your load path by doing:
config.load_paths << File.join(Rails.root, "app", "classes")
If you're using passenger or JRuby, you probably also want to add your path to the eager load paths:
config.eager_load_paths << File.join(Rails.root, "app", "classes")
The bottom-line is that once you get to a point in Rails where you find yourself asking this question, it's time to beef up your Ruby chops and start modeling classes that aren't just the MVC classes that Rails gives you by default.
Update: This answer applies to Rails 2.x and higher.
Update: The use of Concerns have been confirmed as the new default in Rails 4.
It really depends on the nature of the module itself.
I usually place controller/model extensions in a /concerns folder within app.
# concerns/authentication.rb
module Authentication
...
end
# controllers/application_controller.rb
class ApplicationController
include Authentication
end
# concerns/configurable.rb
module Configurable
...
end
class Model
include Indexable
end
# controllers/foo_controller.rb
class FooController < ApplicationController
include Indexable
end
# controllers/bar_controller.rb
class BarController < ApplicationController
include Indexable
end
/lib is my preferred choice for general purpose libraries. I always have a project namespace in lib where I put all application-specific libraries.
/lib/myapp.rb
module MyApp
VERSION = ...
end
/lib/myapp/CacheKey.rb
/lib/myapp/somecustomlib.rb
Ruby/Rails core extensions usually take place in config initializers so that libraries are only loaded once on Rails boostrap.
/config/initializer/config.rb
/config/initializer/core_ext/string.rb
/config/initializer/core_ext/array.rb
For reusable code fragments, I often create (micro)plugins so that I can reuse them in other projects.
Helper files usually holds helper methods and sometimes classes when the object is intended to be used by helpers (for instance Form Builders).
This is a really general overview. Please provide more details about specific examples if you want to get more customized suggestions. :)
... the tendency to make huge
ActiveRecord subclasses and huge
controllers is quite natural ...
"huge" is a worrisome word... ;-)
How are your controllers becoming huge? That's something you should look at: ideally, controllers should be thin. Picking a rule-of-thumb out of thin air, I'd suggest that if you regularly have more than, say, 5 or 6 lines of code per controller method (action), then your controllers are probably too fat. Is there duplication that could move into a helper function or a filter? Is there business logic that could be pushed down into the models?
How do your models get to be huge? Should you be looking at ways to reduce the number of responsibilities in each class? Are there any common behaviours you can extract into mixins? Or areas of functionality you can delegate to helper classes?
EDIT: Trying to expand a bit, hopefully not distorting anything too badly...
Helpers: live in app/helpers and are mostly used to make views simpler. They're either controller-specific (also available to all views for that controller) or generally available (module ApplicationHelper in application_helper.rb).
Filters: Say you have the same line of code in several actions (quite often, retrieval of an object using params[:id] or similar). That duplication can be abstracted first to a separate method and then out of the actions entirely by declaring a filter in the class definition, such as before_filter :get_object. See Section 6 in the ActionController Rails Guide Let declarative programming be your friend.
Refactoring models is a bit more of a religious thing. Disciples of Uncle Bob will suggest, for example, that you follow the Five Commandments of SOLID. Joel & Jeff may recommend a more, er, "pragmatic" approach, although they did appear to be a little more reconciled subsequently. Finding one or more methods within a class that operate on a clearly-defined subset of its attributes is one way to try identifying classes that might be refactored out of your ActiveRecord-derived model.
Rails models don't have to be subclasses of ActiveRecord::Base, by the way. Or to put it another way, a model doesn't have to be an analogue of a table, or even related to anything stored at all. Even better, as long as you name your file in app/models according to Rails' conventions (call #underscore on the class name to find out what Rails will look for), Rails will find it without any requires being necessary.
Here's an excellent blog post about refactoring the fat models that seem to arise from the "thin controller" philosphy:
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Basic message is "Don’t Extract Mixins from Fat Models", use service classes instead, the author provides 7 patterns to do so