Archive for the ‘ActiveRecord’ Category

Advanced Model Based searches in rails

Monday, July 21st, 2008

After watching a railscast episode on advanced searching I thought I would give it a try. So I came up with a slightly modified version that would handle my search.

Model

class ExportSearch
 
  def timecards
    find_cards
  end
 
  def users(u)
    @u = u
  end
 
  def projects(p)
    @p = p
  end
 
  def tasks(t)
    @t = t
  end
 
  def dates(date1, date2)
    @d1 = date1
    @d2 = date2
  end
 
  def clients(c)
    @c = c
  end
 
private
 
  def find_cards
    TimeCard.find(:all, :conditions => conditions, :include => {:task => :project}, :order => :date)
  end
 
  def projects_conditions
    ["tasks.project_id IN (?)", @p] unless @p.blank?
  end
 
  def client_conditions
    ["projects.client_id IN (?)", @c] unless @c.blank?
  end
 
  def date_conditions
    ["date BETWEEN ? AND ?", @d1, @d2] unless (@d1.blank? || @d2.blank?)
  end
 
  def task_conditions
    ["task_id IN (?)", @t] unless @t.blank?
  end
 
  def users_conditions
    ["user_id IN (?)", @u] unless @u.blank?
  end
 
  def conditions
    [conditions_clauses.join(' AND '), *conditions_options]
  end
 
  def conditions_clauses
    conditions_parts.map { |condition| condition.first }
  end
 
  def conditions_options
    conditions_parts.map { |condition| condition[1..-1] }.flatten
  end
 
  def conditions_parts
    private_methods(false).grep(/_conditions$/).map { |m| send(m) }.compact
  end
end

Controller

    search = ExportSearch.new
    search.users(params[:export][:users].join(',')) unless params[:export][:users].blank?
    search.tasks(params[:export][:tasks].join(',')) unless params[:export][:tasks].blank?
    search.projects(params[:export][:projects].join(',')) unless params[:export][:projects].blank?
    search.dates(start_date, end_date)
 
    @time_cards = search.timecards

Merging a :has_many relationship into one instance

Thursday, July 10th, 2008

So the problem is that I have an ActiveRecord model that has a :has_many relationship to another model (we’ll call this one object), but when I am in the view context I didn’t want to have to loop through the object each time to determine which data was being displayed. Object has many attributes (approximately 30) and many are often null for a given instance. So I decided to add a method to my model to loop through all of objects and determine which data should be included. Pretty much the rule was that if there was no data for a particular attribute temporarily save it to a copy of the object and then return that. This is what I came up with.

  def object
    tmp = objects.first
    objects.each {|o| tmp.attributes.each {|key, value| tmp[key] = o[key] if value.blank? && key != 'id'}}
    tmp.freeze
  end

However there was a flaw here. Every time I would view the page all of the data in the objects was getting overwritten with one copy of it. After banging my head on the desk it was realized that tmp[key] = o[key] was actually writing the changes to the database permanently rewriting all of the objects (which still seems counter intuitive to me, because it seems like only the first record should have been the one changing). But the solution was pretty simple. The working method is as follows.

  def object
    tmp = Object.new
    objects.each {|o| tmp.attributes.each {|key, value| tmp[key] = o[key] if value.blank? && key != 'id'}}
    tmp.freeze
  end

Microsoft WebDav opens document as Read-Only when using RailsDav

Tuesday, July 1st, 2008

I had been working on a project in which we wanted to utilize WebDAV (namely for editing Word & Excel Documents that were saved in our application). In order to do this we decided to use a plugin from liverail.net that can be found here. It was pretty easy to hook up after a little direction from a guy over at Benryan Inc [apologies I cannot find a link for them], but there was a major issue. When opening a document through the ActiveX controller for editing it was opening in Read-Only mode.

After a few starts and stops, many hours of reading through the webdav documentation, and browsing through the http traffic using Fiddler - it was determined that locking was the issue.

(more…)

Rails 2.1 broke my mysql foreign keys!

Tuesday, June 24th, 2008

Rails 2.1 introduced in the MySQL Adapter “smart integer columns.” The idea was to use the :limit option to determine whether a smallint, int, or bigint should be used. This is something that the Postgres adapter had already previously implemented. The relevant code in activerecord/lib/active_record/connection_adapters/mysql_adapter.rb is:

  # Maps logical Rails types to MySQL-specific data types.
  def type_to_sql(type, limit = nil, precision = nil, scale = nil)
    return super unless type.to_s == 'integer'

    case limit
    when 0..3
      "smallint(#{limit})"
    when 4..8
      "int(#{limit})"
    when 9..20
      "bigint(#{limit})"
    else
      'int(11)'
    end
  end

Mirko Froehlich suggests monkey patching this function. Timothy Jones blogged about it.

To monkey-patch this, just drop a file (fix_mysql_adapter.rb) into your initializers/ directory, as such:

(more…)