Posts Tagged ‘rails models’

calling named_scope in a loop doesn’t seem to work in rails 2.1.0 ?

#  # Raises NoMethodError: undefined method `processing'
#  %(pending processing complete error).each do |s|
#    named_scope s.to_sym,
#      :conditions => ["state = ?", s],
#      :order => "priority, created_at"
#  end

named_scope :pending,
:conditions => "state = 'pending'",
:order => "priority, created_at"

named_scope :processing,
:conditions => "state = 'processing'",
:order => "priority, created_at"

named_scope :complete,
:conditions => "state = 'complete'",
:order => "priority, created_at"

named_scope :errorneous,
:conditions => "state = 'error'",
:order => "priority, created_at"

named_scope features and gotchas

# Examples mostly taken from Ryan Daigle's blog.
# http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality
# this shall serve as a reminder for me!

# WORKS but actually breaks coding conventions
# well, at least in most cases if you respect print margins ;)
# (multiline blocks/lambdas(?) are supposed to be enclosed in do/end

named_scope :created_by_account, lambda { |account|
  { :conditions => [ "created_by = ?", account.id ] }
}

# DOES NOT WORK
# ArgumentError: tried to create Proc object without a block
# Most probably this is due to the way that named_scope extensions can be defined

named_scope :created_by_account, lambda do |account|
  { :conditions => [ "created_by = ?", account.id ] }
end

# named_scope extensions
# I guess because of the way do/end is used here,
# it is not possible to use do/end with lambda

named_scope :inactive, :conditions => {:active => false} do
  def activate
    each { |i| i.update_attribute(:active, true) }
  end
end

# original comment by Pratik Naik on March 27, 2008 @ 08:56 PM

named_scope :recent, :conditions => ['created_at > ?', 1.week.ago]

# That is really a bad example. As the conditions gets evaluated at load time,
# it’ll end up giving you inaccurate results in production
# where models get loaded only once.

# "Correct" way would be :

named_scope :recent, lambda {
  { :conditions => ['created_at > ?', 1.minute.ago] }
}

# Store named scopes
active = User.scoped(:conditions => {:active => true})
recent = User.scoped(lambda { { :conditions => ['created_at > ?', 1.minute.ago] } })
recent_active = recent.active
recent_active.each { |u| ... }

# count and statistic methods

user.active.recent.count #=> 23
user.active.recent.sum(:age) #=> 391

truncate in active record models

# Put this in a config/initializers file e.g. config/initializers/truncate_helper.rb
# to make truncate available to all ActiveRecord::Base models

# credits for truncate go to:
# http://daniel.collectiveidea.com/blog/2007/7/10/a-prettier-truncate-helper

class ActiveRecord::Base

  # Awesome truncate
  # taken from http://daniel.collectiveidea.com/blog/2007/7/10/a-prettier-truncate-helper
  # -------------------------------------------------------------------------------------
  # First regex truncates to the length, plus the rest of that word, if any.
  # Second regex removes any trailing whitespace or punctuation (except ;).
  # Unlike the regular truncate method, this avoids the problem with cutting
  # in the middle of an entity ex.: truncate("this & that",9)  => "this &am..."
  # though it will not be the exact length.
  def truncate(text, length = 30, truncate_string = "...")
    return if text.nil?
    l = length - truncate_string.chars.length
    text.chars.length > length ? text[/\A.{#{l}}\w*\;?/m][/.*[\w\;]/m] + truncate_string : text
  end
end

subtleties in acts_as_list :scope definitions

# ALWAYS USE '...' instead of "..."
# ---------------------------------
# interpolation will happen later
# when the instance variables are
# in scope (eval magic)

acts_as_list :scope => 'foo_id = #{foo_id} AND bar_id = #{bar_id}'

acts_as_list helper

# include this in application.rb
# or only in the controllers you need it.
# USAGE
# class FooParents::FoosController < ApplicationController
#   include ActsAsListHelper
#   protected
#   def load_foo_parent
#     @foo_parent = FooParent.find(params[:foo_parent_id])
#   end
#   public
#   def create
#     @foo = @foo_parent.foos.build(params[:foo])
#     if @foo.save
#       update_positions :foo_parent, :foo
#       # ...
#     else
#       # ...
#     end
#   end
#   def update
#     @foo = @foo_parent.foos.find(params[:id])
#     update_positions :foo_parent, :foo
#     if @foo.save
#       # ...
#     else
#       # ...
#     end
#   end
#   #...
# end

module ActsAsListHelper
  # support acts_as_list
  def update_positions(parent_name, resource_name)
    parent = instance_variable_get("@#{parent_name.to_s}")
    resource = instance_variable_get("@#{resource_name.to_s}")

    desired_position = params[resource_name.to_sym][:position].to_i
    nr_of_nested_resources = parent.send(resource_name.to_s.pluralize).size

    if desired_position > nr_of_nested_resources + 1 || desired_position < 1
      # correct values that are out of list bounds
      position = nr_of_nested_resources + 1
    else
      position = desired_position
    end
    # acts_as_list call
    resource.insert_at(position)
  end
end

rails plugin that adds default includes to activerecord models

# USAGE
# class Foo < ActiveRecord::Base
#   default_includes = {
#       [ :bar => :baz ],
#       :bam
#     }
#   end
# end
module DefaultIncludeHelper

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

  class InvalidEagerLoadingDefaults < Exception; end

  module ClassMethods

    attr_reader :default_includes

    def find_with_default_includes(*args)
      options = args.extract_options!
      if @default_includes && !options[:include]
        options.merge!(:include => @default_includes)
      end
      find(*(args << options))
    end

    def eager_loading_defaults(defaults)
      unless valid_default_includes?(defaults)
        msg = 'includes must be either a Hash, an Array or a Symbol'
        raise InvalidEagerLoadingDefaults, msg
      end
      @default_includes = defaults
    end

    private 

    def valid_default_includes?(o)
      o.is_a?(Symbol) || o.is_a?(Array) || o.is_a?(Hash)
    end

  end

end

rails plugin that enables activerectord STI with referential integrity

module Snusnu #:nodoc:

  # -------------------------------
  # USAGE
  # -------------------------------
  #
  # class BasicInput < ActiveRecord::Base
  #   inheritance_table :input_types do |map|
  #     # uses 'input_type_id' for :type_id
  #     map.route :type_id => 1, :to_class => "TextInput"
  #     map.route :type_id => 2, :to_class => "NumericInput"
  #   end
  # end
  #
  # or
  #
  # class BasicInput < ActiveRecord::Base
  #   inheritance_table :input_types, :type_column => :type do |map|
  #     # uses 'type' as column for :type_id
  #     map.route :type_id => 1, :to_class => "TextInput"
  #     map.route :type_id => 2, :to_class => "NumericInput"
  #   end
  # end

Read more »

DRYing associations and behavior

module CommonBehaviour
  def self.included(base)
    base.class_eval <<-EOC
      belongs_to :foo
      has_many :bars
      delegate :baz, :to => :survey_execution
    EOC
    base.send :include, InstanceMethods
  end

  module InstanceMethods
    def bla
      p 'bla'
    end
  end
end

class OneOfCommon < ActiveRecord::Base
  include CommonBehaviour
end

nested includes in find

# in your model

class << self

  INCLUDE_OPTIONS = [
    { :section_application => [
      { :chapter_application => [
        { :questionnaire_application => [
          { :survey_application => :survey },
          :questionnaire,
        ] },
        :chapter,
      ] },
      :section
    ] },
    :question,
    :input_type,
    :time_line,
    :unit
  ]

  def find_with_includes(*args)
    find_without_includes args.pop, :include => INCLUDE_OPTIONS
  end

  alias_method_chain :find, :includes

end

# in your controller

def index
  @models = Model.find_with_includes(:all)
end

CUDdly design (as coined by Pivotal Labs)

Pivotal Labs coin the term CUDdly Models for refactoring public model actions with side effects, into proper ActiveRecord callbacks, thus leveraging the power of encapsulation, transactions, consistent interface, and (activerecord) lifecycle power.

See this for a more thorough explanation.

« Older Entries