I understand that application_controller.rb is the place to put all the methods, etc that you would like made available in all your controllers since they all inherit from this class. Great.
But what is the equivalent for Models? In other words, I want a place where I can create a couple of super classes that my models will inherit from.
For example, I have a method that searches different tables for entries in all CAPS via REGEXP in Mysql. I'd like to be able to create the method only once and call it for different tables/models.
What is the Rails way of doing this?
I thought I could create a class that would inherit from ActiveRecord::Base (as all models do) , put the methods in there and then inherit all my models from that class. But thought there would surely be a better way to do it.
Thanks.
Edit
Per Semyon's answer I'm editing the post to show the routes I am using. It works now:
# models/dvd.rb
require 'ModelFunctions'
class Dvd < ActiveRecord::Base
extend ModelFunctions
...
end
# lib/ModelFunctions.rb
module ModelFunctions
def detect_uppercase(object)
case object
...
where("(#{field} COLLATE utf8_bin) REGEXP '^[\w[:upper:]]{5,}' ").not_locked.reorder("LENGTH(#{field}), #{table}.#{field} ASC")
end
end
In config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
Take a look at mixins, for example here:
http://ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html
In a Rails app you could create a module in the lib directory that defines your methods and then include it in your models.
EDIT: To be specific for your example, you're trying to define a class method. You can do this in a mixin like this:
module Common
module ClassMethods
def detect_uppercase(object)
case object
when 'dvd'
field = 'title'
...
end
where("(#{field} COLLATE utf8_bin) REGEXP '^[\w[:upper:]] {5,}').not_locked.reorder('LENGTH(title), title ASC')"
end
end
def self.included(base)
base.extend(ClassMethods)
end
end
Now when you include Common in your model, that model's class will be extended to include the new class methods, and you should be able to call Dvd.detect_uppercase.
Put the reusable method in some module next to your Dvd class. You can move it in a separate file later.
# app/models/dvd.rb
module CaseInsensitiveSearch
def case_insensitive_search(field, value)
# searching field for value goes here
end
end
class Dvd
end
After extending a class with the module you can use case_insensitive_search on the class. Including the module will make case_insensitive_search an instance method which is not what you want.
class Dvd
extend CaseInsensitiveSearch
end
Dvd.case_insensitive_search("title", "foo")
And of course you can use it inside Dvd class.
class Dvd
def self.search(query)
case_insensitive_search("title", query)
end
end
Dvd.search("foo")
Now when you made sure it works, you will probably want to move it in a separate file and use it across multiple classes. Place it in lib/case_insensitive_search.rb and make sure you have this line in config/application.rb:
config.autoload_paths += %W(#{config.root}/lib)
Now you can require it anywhere you want to use it:
require 'case_insensitive_search'
class Dvd
extend CaseInsensitiveSearch
end
The last thing I'd like to suggest. Create multiple modules with meaningful names. So instead of CommonModel have CaseInsensitiveSearch and so on.
Related
I've been bashing my head against this for about three days now. I've created a class that models html pages and tells cucumber step definitions where to populate form data:
class FlightSearchPage
def initialize(browser, page, brand)
#browser = browser
#start_url = page
#Get reference to config file
config_file = File.join(File.dirname(__FILE__), '..', 'config', 'site_config.yml')
#Store hash of config values in local variable
config = YAML.load_file config_file
#brand = brand #brand is specified by the customer in the features file
#Define instance variables from the hash keys
config.each do |k,v|
instance_variable_set("##{k}",v)
end
end
def method_missing(sym, *args, &block)
#browser.send sym, *args, &block
end
def page_title
#Returns contents of <title> tag in current page.
#browser.title
end
def visit
#browser.goto(#start_url)
end
def set_origin(origin)
self.text_field(#route[:attribute] => #route[:origin]).set origin
end
def set_destination(destination)
self.text_field(#route[:attribute] => #route[:destination]).set destination
end
def set_departure_date(outbound)
self.text_field(#route[:attribute] => #date[:outgoing_date]).set outbound
end
# [...snip]
end
As you can see, I've used instance_variable_set to create the variables that hold the references on the fly, and the variable names and values are supplied by the config file (which is designed to be editable by people who aren't necessarily familiar with Ruby).
Unfortunately, this is a big, hairy class and I'm going to have to edit the source code every time I want to add a new field, which is obviously bad design so I've been trying to go a stage further and create the methods that set the variable names dynamically with define_method and this is what's kept me awake until 4am for the last few nights.
This is what I've done:
require File.expand_path(File.dirname(__FILE__) + '/flight_search_page')
class SetFieldsByType < FlightSearchPage
def text_field(config_hash)
define_method(config_hash) do |data|
self.text_field(config_hash[:attribute] => config_hash[:origin]).set data
end
end
end
The idea is that all you need to do to add a new field is add a new entry to the YAML file and define_method will create the method to allow cucumber to populate it.
At the moment, I'm having problems with scope - Ruby thinks that define_method is a member of #browser. But what I want to know is: is this even feasible? Have I totally misunderstood define_method?
Do you mean that you'd expect to see the requires and file loads outside the class definition?
No, inside the class definition. Ruby class declarations are just code that execute in the order it's seen. Things like attr_accessor are just class methods that happen to do things to the class being defined, as it's being defined. This seems like what you want to do.
In your case you'd read the YAML file instead, and run your own logic to create accessors, build any backing data required, etc. I don't totally grok the usecase, but it doesn't sound unusual or difficult--yet.
That said, how much "convenience" do you get by putting these definitions in a YAML file? Consider something like I did once to create page instances I used to drive Watir:
class SomePage < HeavyWatir
has_text :fname # Assumed default CSS accessor pattern
has_text :whatever, accessor: 'some accessor mechanism', option: 'some other option'
end
The has_xxx were class methods that created instance variable accessors (just like attr_accessor does), built up some other data structures I used to make sure all the things that were supposed to be on the page actually were, and so on. For example, very roughly:
page = SomePage.new
page.visit
if page.missing_fields?
# Do something saying the page isn't complete
end
It sounds like you want something vaguely similar: you have a bunch of "things" you want to give to the class (or a sub-class, or you could mix it in to an arbitrary class, etc.)
Those "things" have additional functionality, that functionality works in multiple ways, like:
Things-that-happen-during-definition
E.g., has_text adds the name to a class instance hash ofthe page's metadata, like field names.
Things-that-happen-during-usage
E.g., when fname= is called set a flag in the instance's metadata saying the setter was called.
This is an appropriate case for metaprogramming, but it looks like you're going about it the wrong way.
First of all, is there going to be a different config file for each instance of FlightSearchPage or just one config file that controls all pages? It looks like you're loading the same config file regardless of the arguments to initialize so I'm guessing your case is the former.
If that is so, you need to move all of your metaprogramming code into the class (outside method definitions). I.e. when the class is defined, you want it to load the config file and then each instance is created based on that config. Right now you have it reloading the config file every time you create an instance, which seems incorrect. For example, define_method belongs to Module so it should appear in class scope, rather than in an instance method.
On the other hand, if you do want a different config for each instance, you need to move all of your metaprogramming code into the singleton class e.g. define_singleton_method rather than define_method.
I always have a brain cramp when it comes to this. I'm creating a module to mix in to model-like classes but it needs to keep exactly one copy of serializable attributes per class. So here is the code (that doesn't work).
module Checkin
module Model
def self.included(base)
base.extend(ClassMethods)
end
##serialiable_attrs = [] <== really not the right place
module ClassMethods
def serializable(*attrs)
attrs.each{|attr| ##serializable_attrs << attr} # Is this ## or just #?
end
end
def serialize!
##serializable_attrs.each{|a| do_something_with(a)} # <== Will this work?
end
end
end
class Person
include Checkin::Model
serializable :first_name, :original_name, :last_name, :checked_in, :people_attending
# etc., etc.
end
What I'm wrangling with are two things:
How to define my mix-in such that a class variable magically springs into existence; and
How to access that variable both in my ClassMethods module and in the (for lack of a better term) instance methods part of the module.
Note that I've settled on a mix-in technique rather than inheritance because I will have Validatable, Persistable, Serializable and so on. Also, I know there are all sorts of validation and persistence layers available that are well tested and heavily used. This is a different beast and I really should know who to do this in my sleep, right?
Any Ruby wizards who can help me understand how to do this or suggest a different direction to approach this problem from, I appreciate the help!
Try removing the class variable, and adding this to the module ClassMethod:
def self.extended(klass)
klass.instance_variable_set("#serializable_attrs", [])
end
And changing the double-# to single in serializable. And change serialize! to this:
self.class.instance_variable_get("#serializable_attrs").each{|a| do_something_with(a)}
Let's say I have a bunch of related functions that have no persistent state, say various operations in a string differencing package. I can either define them in a class or module (using self) and they can be accessed the exact same way:
class Diff
def self.diff ...
def self.patch ...
end
or
module Diff
def self.diff ...
def self.patch ...
end
I can then do Diff.patch(...). Which is 'better' (or 'correct')?
The main reason I need to group them up is namespace issues, common function names are all used elsewhere.
Edit: Changed example from matrix to diff. Matrix is a terrible example as it does have state and everyone started explaining why it's better to write them as methods rather than answer the actual question. :(
In your two examples, you are not actually defining methods in a Class or a Module; you are defining singleton methods on an object which happens to be a Class or a Module, but could be just about any object. Here's an example with a String:
Diff = "Use me to access really cool methods"
def Diff.patch
# ...
end
You can do any of these and that will work, but the best way to group related methods is in a Module as normal instance methods (i.e. without self.):
module Diff
extend self # This makes the instance methods available to the Diff module itself
def diff ... # no self.
def patch ...
end
Now you can:
use this functionality from within any Class (with include Diff) or from any object (with extend Diff)
an example of this use is the extend self line which makes it possible to call Diff.patch.
even use these methods in the global namespace
For example, in irb:
class Foo
include Diff
end
Foo.new.patch # => calls the patch method
Diff.patch # => also calls Diff.patch
include Diff # => now you can call methods directly:
patch # => also calls the patch method
Note: the extend self will "modify" the Diff module object itself but it won't have any effect on inclusions of the module. Same thing happens for a def self.foo, the foo won't be available to any class including it. In short, only instance methods of Diff are imported with an include (or an extend), not the singleton methods. Only subclassing a class will provide inheritance of both instance and singleton methods.
When you actually want the inclusion of a module to provide both instance methods and singleton methods, it's not completely easy. You have to use the self.included hook:
module Foo
def some_instance_method; end
module ClassMethods
def some_singleton_method; end
end
def self.included(base)
base.send :extend, ClassMethods
end
def self.will_not_be_included_in_any_way; end
end
class Bar
include Foo
end
# Bar has now instance methods:
Bar.new.some_instance_method # => nil
# and singleton methods:
Bar.some_singleton_method # => nil
The main difference between modules and classes is that you can not instantiate a module; you can't do obj = MyModule.new. The assumption of your question is that you don't want to instantiate anything, so I recommend just using a module.
Still you should reconsider your approach: rather than using arrays of arrays or whatever you are doing to represent a Matrix, it would be more elegant to make your own class to represent a matrix, or find a good class that someone else has already written.
Ruby Modules are used to specify behaviour, pieces of related functionality.
Ruby Classes are used to specify both state and behaviour, a singular entity.
There is a maxim in software design that says that code is a liability, so use the less code possible. In the case of Ruby, the difference in code lines is cero. So you can use either way (if you don't need to save state)
If you want to be a purist, then use a Module, since you won't be using the State functionality. But I wouldn't say that using a class is wrong.
As a trivia info: In Ruby a Class is a kind of Module.
http://www.ruby-doc.org/core-1.9.3/Class.html
The following also works
Matrix = Object.new
def Matrix.add ...
def Matrix.equals ...
That's because so-called "class methods" are just methods added to a single object, and it doesn't really matter what that object class is.
As a matter of form, the Module is more correct. You can still create instances of the class, even if it has only class methods. You can think of a module here as a static class of C# or Java. Classes also always have the instance related methods (new, allocate, etc.). Use the Module. Class methods usually have something to do with objects (creating them, manipulating them).
Given the following:
class User; attr_accessor :roles; end
module RegisteredUser
def default_context
Submission
end
end
module Admin
def default_context
Review
end
end
current_user = User.new
current_user.roles = ["registered_user", "admin"]
current_user.roles.each do |role|
role_module = role.gsub(/ /, '_').camelize
if module_exists?(role_module)
current_user.extend role_module.constantize
end
end
context = self.extend current_user.default_context
Is there a way to set the priority of User#default_context? That is, can I say that the Admin#default_context always takes priority over RegisteredUser#default_context regardless of the order in which current_user is extended?
method_added is in Module.
I actually meant included, not extended, but both are also in Module.
The mechanism would revolve around doing something like this:
module Foo
def self.included(base)
base.extend(FooMethods)
end
module FooMethods
def bar
# Whatever
end
end
end
Inside Foo.included you can determine, based on arbitrary criteria, whether or not the methods in question should be added to base (the entity including the module).
In your case, you could check to see if a "higher priority" module was already included, or see if the module is the "higher priority" module. Based on that you'd decide whether or not to add the methods.
Since an Admin is also a RegisteredUser, I would do
module Admin
include RegisteredUser
...
end
and then only
current_user.extend Admin
I am not sure if this is the correct way. If Admin and RegisteredUser were classes, it would make sense making Admin inherit from RegisteredUser. In case of modules, dunno.
You cannot; in Ruby the order of module inclusion is the order in which modules are searched (after the current class, before parent classes). The only way to change the 'priority' is to include the modules in the order you want, or to move them to a parent class.
Although not pure Ruby, you can use the Remix library by banisterfiend to change module ordering (or unmixin a module, or...other things).
I have a large class with lots of methods and it's starting to get a bit unorganized and hard to navigate. I'd like to break it up into modules, where each module is a collection of class and instance methods. Perhaps something like this:
UPDATE: I've now realized that this is a pretty poor example. You probably wouldn't want to move validations or attributes out of the core class.
class Large
include Validations
include Attributes
include BusinessLogic
include Callbacks
end
After reading Yehuda's post about Better Ruby Idioms, I'm curious how others are tackling this problem. Here's the two methods I can think of.
First Method
module Foo
module Validations
module ClassMethods
def bar
"bar"
end
end
module InstanceMethods
def baz
"baz"
end
end
end
class Large
extend Validations::ClassMethods
include Validations::InstanceMethods
end
end
Second Method
module Foo
module Validations
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def bar
"bar"
end
end
def baz
"baz"
end
end
class Base
include Validations
end
end
My questions are:
Is there a better way to do this?
How do you get a one-liner module mixin for a set of class/instance methods with the least amount of magic?
How do you namespace these modules to the base class without namespacing the class itself?
How do you organize these files?
Breaking a class into modules, while tempting (because it's so easy in Ruby), is rarely the right answer. I usually regard the temptation to break out modules as the code's way of telling me it wants to be split into more tightly-focussed classes. A class that's so big you want to break it into multiple files is pretty much guaranteed to be violating the Single Responsibility Principle.
EDIT: To elaborate a bit on why breaking code into modules is a bad idea: it's confusing to the reader/maintainer. A class should represent a single tightly-focussed concept. It's bad enough when you have to scroll hundreds of lines to find the definition of an instance method used at the other end of a long class file. It's even worse when you come across an instance method call and have to go looking in another file for it.
After doing what Avdi said, these are the things I would do before putting anything into a module:
Whether this module can or will be used in any other class?
Would it make sense to extract the functionality of these modules into a different or base class?
If the answer for 1 is no and 2 is yes then IMHO that indicates to better have a class rather a module.
Also, I think putting attributes in a module is conceptually wrong because classes never share their attributes or instance variables or in other words their internal state with any other class. The attributes of a class belongs to that class only.
Business logics do definitely belong to the class itself and if the business logic of class A has some common responsibilities with class C then that needs to be extracted into a base class to make it clear instead of just putting it into a module.
The standard idiom seems to be
foo.rb
foo/base.rb
foo/validations.rb
foo/network.rb
foo/bar.rb
and foo.rb would be something like
class Foo
include Foo::Base
include Foo::Validations
include Foo::Network
include Foo::Bar
end
This is the standard idiom, and it works fairly well for letting you break things up. Don't do class methods vs instance methods. Those are generally pretty arbitrary distinctions, and you're better off putting code that deals with similar subjects together. That will minimize how many files you have to touch for any given change.
BEWARE: Rails can get confused by nesting models like this, at least if everything were classes. I think it'll do better with all the nested files just being modules, but you'll have to see. I'm still suggesting this because it's the normal idiom used by the Ruby community, but you may have to avoid having both a foo.rb and a foo/ directory amongst your Rails models (if that's the kind of class you're talking about).
Although including different modules will work, it is generally more troublesome than simply reopening the class in multiple places.
There is a (very simple) gem that you can use to makes this as pretty as can be: concerned_with
Example (from the readme)
# app/models/user.rb
class User < ActiveRecord::Base
concerned_with :validations,
:authentication
end
# app/models/user/validations.rb
class User < ActiveRecord::Base
validates_presence_of :name
end
#app/models/user/authentication.rb
class User < ActiveRecord::Base
def self.authenticate(name, password)
find_by_name_and_password(name, password)
end
end
I tend to use Ruby's duck typing approach to interfaces, which basically allows you to send any message to any object, which then evaluates what to do with it.
This approach allows me to stick to the same pattern Avdi mentions, keeping classes small and concise- only ever being responsible for one thing.
The great thing about Ruby is that you can delegate responsibilities to other concise classes, without muddling any of the logic together. For example:
class Dog
def initialize(name)
#name = name
end
def bark
"woof"
end
def fetch(object)
"here's that #{object}"
end
def sit
"sitting down"
end
private
attr_accessor :name
end
Here we have my dog class that has loads of dog related methods. They're all specific to dog, so could happily reside here. However, there would be a problem if these methods got a bit complex, calling other methods or perhaps this dog learns a bunch of new tricks!? So I could separate these out into their own classes and then delegate responsibility to those, like so:
class Tricks
def initialize(name)
#name = name
end
def fetch(object)
"here's that #{object}"
end
def sit
"sitting down"
end
def come_when_called(my_name)
"I'm coming" if my_name == name
end
def put_toy_away(object)
"#{fetch(object)}, I'll put it away"
end
private
attr_reader :name
end
class Dog
def initialize(name)
#name = name
end
delegate :sit, :fetch, :come_when_called, :put_away_toy, to: :tricks_klass
def bark
"woof"
end
private
attr_accessor :name
def tricks_klass
#tricks_klass ||= Tricks.new(name)
end
end
So now, that Dog class really starts to behave like an interface to dog-related behaviors, whilst these tricks are no longer coupled to it. This'll make testing easier by being able to instantiate a Tricks object and test it more generically, without the need for a Dog (because they don't always listen).
Now, we could have a Cat class that delegates responsibility to this Tricks class as well- although, that'd be one smart Cat!
You could also now use the Tricks class on its own- that's the power encapsulating single behavior its own class. You could even separate these behaviors even further- but only you as the developer know if that's worth while!