Shared Model Methods

Hi all,

I just have a question about shared model methods. I have a method that
will be used for quite a few models in my application (once I’ve cleaned
it up a bit). Where can I place shared model methods? I know that
controllers can use helpers or even the application_controller. But,
what do models use for a shared mechanism? Is it config/initialize?

Can someone explain a quick process for it?

Here’s an example of a shared model method that I will be using:

def self.list(search, page, orderby, sortby, numteams, datevar)
datevar = todaysdate if datevar.empty? || datevar.nil? ||
DATE_VALIDATE_REG.match(datevar).nil?
convert_time = datevar.to_time.beginning_of_week
week_start_date = convert_time.to_date.strftime(’%Y-%m-%d’)
named_scope :compiled_on_week, lambda { { :conditions =>
[‘compiled_on >= ? and compiled_on <= ?’, week_start_date, datevar] } }
orderby = “rank” if orderby.nil? || orderby.empty?
orderall = (sortby != ‘asc’ && sortby != nil) ? “DESC” : “ASC”
compiled_on_week.paginate :joins => :team, :conditions => [‘name
like ?’, “%#{search}%”], :order => orderby + " #{orderall}", :per_page
=> numteams, :page => page
end

On Jul 1, 1:26 pm, “Älphä Blüë” [email protected]
wrote:

Hi all,

I just have a question about shared model methods. I have a method that
will be used for quite a few models in my application (once I’ve cleaned
it up a bit). Where can I place shared model methods? I know that
controllers can use helpers or even the application_controller. But,
what do models use for a shared mechanism? Is it config/initialize?

Yes, just use Ruby modules.

module SharedMethods

def list
# …
end
end

And in your model,

class MyModel < ActiveRecord::Base

extend SharedMethods

end

Does this help?

Jeff

Rails for Everyone: Oct 24, 2009 in Chicago:
http://www.purpleworkshops.com/workshops/rails-for-everyone

Thanks a lot Jeff - yeah that’s what I’m looking for. Does the ruby
module have to belong in a certain place in my project to be usable by
other models?

I figured it out. I actually made it simpler for me since I will be
using a lot of methods (duplicate) for 37 different models.

I just created a plugin…

script/generate plugin template_searches

init.rb added…

ActiveRecord::Base.send :include, TemplateSearches

template_searches.rb added…

module TemplateSearches
def self.included(base)
base.extend(ClassMethods)
end

module ClassMethods

My Methods…

end
end

Removed the duplicate code and restarted and all is working well.

Älphä Blüë wrote:

Hi all,

I just have a question about shared model methods. I have a method that
will be used for quite a few models in my application (once I’ve cleaned
it up a bit). Where can I place shared model methods? I know that
controllers can use helpers or even the application_controller. But,
what do models use for a shared mechanism? Is it config/initialize?

Can someone explain a quick process for it?

Depending on how big the sharing ends up (my app is about 85% shared
functionality among models), you can always create an abstract model
class that defines those capabilities, then inherit concrete models from
that.

class GenericModel < ActiveRecord::Base
self.abstract_class = true

generic implementations shared by all models

my app has some 30 ‘generic’ model methods, relationship

management, cache management, pdf generation, etc

end

class Project < GenericModel

project-specific methods

project has only 5, 2 of which override GenericModel

definitions

end

You can do the same thing with controllers as well…
GenericController has all the common stuff (index, show, edit, etc, etc)
ProjectsController has just the project specific stuff.

Whatever works for you.

Wow, I like that better than the plugin. I guess plugins would be good
if you need to use similar things in multiple projects. But, if what
you are doing only applies to one project, the inherited
models/controllers are nice!

I just created an parent model and then made my test model a child of
it. All I had to do was make sure that the methods in the parent model
were named self.methodname and it worked like a charm.

I still have the question though about doing the same type of thing with
a controller. How are the instance variables handled when doing that?

Taking a simpler note:

def new
@rushing_offense = RushingOffense.new

respond_to do |format|
  format.html # new.html.erb
  format.xml  { render :xml => @rushing_offense }
end

end

If I take all the RESTful methods out of the child controller and place
them into the parent, how will this method appear (formatted wise) in
the parent controller. This is how it appears in the child controller.

Do I have to use something like @self.controller_name or … ?

Thanks - that’s great information to know too.

I’ve basically been working heavily on “one” controller and model to
fine-tune it exactly the way it needs to work. It has a lot of methods
and control functionality associated with it. I’m close to finishing
the default MVC and so I’m trying to perform some cleanup work in
preparation for the other MVC templates.

With regards to the 37 MVC templates that are similar:

The controllers will be exact:
The views will be exact (minus table columns (some will have more some
less)
The models will be almost exact with some shared methods…

I’ve already moved the shared methods from the models to the new plugin
I created and tested (all appears well).

I’ve cleaned up a lot of the views by creating a table_helper that
defines pagination, sorting, etc.

However, the controllers are my next step.

I never thought about a generic controller option. So, let me make sure
I understand you correctly:

My controllers are restful. Each of them houses the exact same items,
including the index:

def index
validate_date_form
@rushing_offenses = RushingOffense.list(params[:search],
params[:page], params[:orderby], params[:sortby], params[:numteams],
params[:compiled_on])
@showall = params[:numteams]
@searchteams = params[:search]

respond_to do |format|
  format.html # index.html.erb
  format.xml  { render :xml => @rushing_offenses }
end

end

The only differences per each controller are the instance variables.
So, how are instanced variables handled between generic/project based
controllers?

As a short elucidation, consider a stripped down version of the index
method in the GenericController – all the models use this vanilla index
method from
GenericController.

def index
# index_setup is a routine that looks at session and params to
# return the proper order claause, condition clause, and a filtered
# list of ids for one or two special cases
order, cond, filtered = index_setup session, params
# user_rows is a user-defined rows per display table (we have widely
# varying monitor resolutions in use at the office)
rows = user_rows
# since I unfortunately named one model Filter, I have to direct to
# my filter class, not Rails’ class
#
# but the views for all the models work in terms of @objects
# as the instance var for returned models
if params[:controller] == ‘filters’
@objects = ::Filter.paginate :conditions => cond, :page =>
params[:page], :per_page => rows, :order => order
else
# constantize rules…
@objects =
params[:controller].singularize.camelcase.constantize.paginate
:conditions => cond, :page => params[:page], :per_page => rows, :order
=> order
end
end

but that should get you the idea.

er the format.xml is not @rushing_offenses it’s @objects as well…

This is great :slight_smile:

Wow, that’s pretty powerful stuff there.

I created a Universal Templates controller with the following test:

class UniversalTemplatesController < ApplicationController

def index
validate_date_form
@objects =
params[:controller].singularize.camelcase.constantize.list(params[:search],
params[:page], params[:orderby], params[:sortby], params[:numteams],
params[:compiled_on])
@showall = params[:numteams]
@searchteams = params[:search]

respond_to do |format|
  format.html # index.html.erb
  format.xml  { render :xml => @rushing_offenses }
end

end

end

Changed my rushing_offenses_controller to…

class RushingOffensesController < UniversalTemplatesController
before_filter :set_pagetitle

def set_pagetitle
@pagetitle = “NCAA Division I : Rushing Offense Statistics”
end

end

And then changed the @rushing_offenses instance variables to @objects
and it all works great…

I didn’t think you could do this with controllers at all. Amazing -
thanks!!

Glad that it’s working for you.

If I could remember the site where I first read about constantize, I’d
credit that person… I’m just a messenger.

On Thu, Jul 2, 2009 at 9:05 AM, Marnen
Laibow-Koser[email protected] wrote:

Before you get too far with this, you might want to take a look at
make_resourceful, which encapsulates some similar features.

Or as an alternative resource_controller


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Marnen Laibow-Koser wrote:

Älphä Blüë wrote:

Wow, that’s pretty powerful stuff there.

I created a Universal Templates controller with the following test:

class UniversalTemplatesController < ApplicationController
[…]

Before you get too far with this, you might want to take a look at
make_resourceful, which encapsulates some similar features.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

I actually had looked into that yesterday when I was doing searches for
controllers. The big turnoff with it was that it uses haml. Now I know
for the most part many people love using haml because they feel it’s
faster on development and cleaner. For me, it’s not. Html, Xml, Css
are like walking down the street to me. I tried haml a couple of weeks
back and simply hated it. It wasn’t for me. I have a photographic
memory and my brain revolves around code in a set learning process. I
don’t want to reinvent the wheel to make something shorter for something
that’s not broke and properly written.

Thanks for the tip though Marnen.

Älphä Blüë wrote:

Wow, that’s pretty powerful stuff there.

I created a Universal Templates controller with the following test:

class UniversalTemplatesController < ApplicationController
[…]

Before you get too far with this, you might want to take a look at
make_resourceful, which encapsulates some similar features.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On Jul 1, 6:05 pm, Ar Chron [email protected] wrote:

project has only 5, 2 of which override GenericModel

definitions

end

Project.table_name
— generic_models
=> nil

To preserve ARs default table naming and related conventions a model
class MUST inherit directly from ActiveRecord. This is apparently an
artifact of how the AR class is actually assembled from modules “on-
the-fly” as it were. If you do use the generic_model class then you
must provide in each descendant class the actual table name the class
should use. The project class should include this:

—>
class Project < GenericModel

set_table_name “projects” # do not forget to pluralise the table
name!

project-specific methods

project has only 5, 2 of which override GenericModel

definitions

end
<—

HTH

James B. wrote:

To preserve ARs default table naming and related conventions a model
class MUST inherit directly from ActiveRecord. This is apparently an
artifact of how the AR class is actually assembled from modules “on-
the-fly” as it were. If you do use the generic_model class then you
must provide in each descendant class the actual table name the class
should use. The project class should include this:

—>
class Project < GenericModel

set_table_name “projects” # do not forget to pluralise the table
name!

project-specific methods

project has only 5, 2 of which override GenericModel

definitions

end
<—

Interesting… I haven’t encountered any issues, and I haven’t set the
table name in any of my classes. And a test I just did reported the
proper name:

C:\railsworkspace\testbase_sdrndlinuxapp>ruby script/console
Loading development environment (Rails 2.3.2)

Project.table_name
=> “projects”