Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

Peter Cooperx http://www.petercooper.co.uk/

« Newer Snippets
Older Snippets »
Showing 1-10 of 34 total  RSS 

Useful Rake tasks for Subversion setup with Rails

This was originally written by Jake at http://blog.unquiet.net/archives/2005/11/06/helpful-rake-tasks-for-using-rails-with-subversion/ .. but that site seems not to be showing content properly, so I salvaged this from the Google cache. I also added two new lines to make it remove /tmp folder which is now in Rails.

Just dump this into a file called svn.rake in your lib/tasks folder, and use rake configure_for_svn to sort everything out on your initial check out:

desc "Configure Subversion for Rails"
task :configure_for_svn do
  system "svn remove log/*"
  system "svn commit -m 'removing all log files from subversion'"
  system 'svn propset svn:ignore "*.log" log/'
  system "svn update log/"
  system "svn commit -m 'Ignoring all files in /log/ ending in .log'"
  system 'svn propset svn:ignore "*.db" db/'
  system "svn update db/"
  system "svn commit -m 'Ignoring all files in /db/ ending in .db'"
  system "svn move config/database.yml config/database.example"
  system "svn commit -m 'Moving database.yml to database.example to provide a template for anyone who checks out the code'"
  system 'svn propset svn:ignore "database.yml" config/'
  system "svn update config/"
  system "svn commit -m 'Ignoring database.yml'"
  system "svn remove tmp/*"
  system "svn commit -m 'Removing /tmp/ folder'"
  system 'svn propset svn:ignore "*" tmp/'
end
   
desc "Add new files to subversion"
task :add_new_files do
   system "svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add"
end

desc "shortcut for adding new files"
task :add => [ :add_new_files ]

Extending acts_as_taggable for real-world requirements

acts_as_taggable is cool, but it doesn't easily support limits, offsets, tag intersections, arbitrary conditions, etc.. so I created some unit tests and started to extend it. This is where I'm at so far:

module ActiveRecord
  module Acts #:nodoc:
    module Taggable #:nodoc:
      def self.included(base)
        base.extend(ClassMethods)  
      end
      
      module ClassMethods
        def acts_as_taggable(options = {})
          write_inheritable_attribute(:acts_as_taggable_options, {
            :taggable_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s,
            :from => options[:from]
          })
          
          class_inheritable_reader :acts_as_taggable_options

          has_many :taggings, :as => :taggable, :dependent => true
          has_many :tags, :through => :taggings

          include ActiveRecord::Acts::Taggable::InstanceMethods
          extend ActiveRecord::Acts::Taggable::SingletonMethods          
        end
      end
      
      module SingletonMethods
        def find_tagged_with(list, options = {})
          local_options = { :limit => 1000, :offset => 0 }.merge(options)
          find_by_sql([
            "SELECT DISTINCT #{table_name}.* FROM #{table_name}, tags, taggings " +
            "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
            "AND taggings.taggable_type = ? " +
            "AND taggings.tag_id = tags.id AND tags.name IN (?) #{"AND (#{local_options[:conditions]})" if local_options[:conditions]} LIMIT ? OFFSET ?",
            acts_as_taggable_options[:taggable_type], list, local_options[:limit], local_options[:offset]
          ])
        end
        
        def count_tagged_with(list, options = {})
          local_options = {}.merge(options)
          find_by_sql([
            "SELECT COUNT(DISTINCT #{table_name}.#{primary_key}) AS cnt FROM #{table_name}, tags, taggings " +
            "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
            "AND taggings.taggable_type = ? " +
            "AND taggings.tag_id = tags.id AND tags.name IN (?) #{"AND (#{local_options[:conditions]}) " if local_options[:conditions]}",
            acts_as_taggable_options[:taggable_type], list
          ]).first.cnt.to_i
        end

        def find_tagged_with_intersecting(list, options = {})
          local_options = { :limit => 1000, :offset => 0 }.merge(options)
          find_by_sql([
            "SELECT DISTINCT #{table_name}.* FROM #{table_name}, tags, taggings " +
            "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
            "AND taggings.taggable_type = ? " +
            "AND taggings.tag_id = tags.id AND tags.name IN (?) #{"AND (#{local_options[:conditions]}) " if local_options[:conditions]} GROUP BY #{table_name}.id HAVING COUNT(#{table_name}.id) = #{list.size} LIMIT ? OFFSET ?",
            acts_as_taggable_options[:taggable_type], list, local_options[:limit], local_options[:offset]
          ])
        end

        def count_tagged_with_intersecting(list, options = {})
          local_options = {}.merge(options)
          find_by_sql([
            "SELECT COUNT(*) AS cnt FROM (SELECT #{table_name}.#{primary_key} AS cnt FROM #{table_name}, tags, taggings " +
            "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
            "AND taggings.taggable_type = ? " +
            "AND taggings.tag_id = tags.id AND tags.name IN (?) " +
            "#{"AND (#{local_options[:conditions]})" if local_options[:conditions]} " +
            "GROUP BY taggings.taggable_id HAVING COUNT(taggings.taggable_id) = #{list.size}) AS x",
            acts_as_taggable_options[:taggable_type], list
          ]).first.cnt.to_i
        end               
      end
      
      module InstanceMethods
        def tag_with(list)
          Tag.transaction do
            taggings.destroy_all

            Tag.parse(list).each do |name|
              if acts_as_taggable_options[:from]
                send(acts_as_taggable_options[:from]).tags.find_or_create_by_name(name).on(self)
              else
                Tag.find_or_create_by_name(name).on(self)
              end
            end
          end
        end

        def tag_list
          tags.collect { |tag| tag.name.include?(" ") ? "'#{tag.name}'" : tag.name }.join(" ")
        end
      end
    end
  end
end


These are the sorts of tests I'm then doing:

assert_equal 2, Post.find_tagged_with_intersecting(%w{TagOne TagTwo}).size
assert_equal 2, Post.count_tagged_with_intersecting(%w{TagOne TagTwo})
assert_equal 1, Post.find_tagged_with_intersecting(%w{TagOne TagTwo}, :conditions => 'status = 1').size
assert_equal 1, Post.count_tagged_with_intersecting(%w{TagOne TagTwo}, :conditions => 'status = 1')
p = Post.find_tagged_with("TagOne", :conditions => 'status = 1')

Merging POST + GET parameters from WorldPay callback to Rails app

I have no idea why I had to resort to this, but I did. params (and parameters) were only getting the URL parameters on a POST callback from WorldPay! So I forced the issue..

params.merge!(Hash[*request.raw_post.scan(/(\w+)\=(.+?)&/).flatten]) 

Rails Credit Card Model

A great example of a 'Credit Card' model I found on Pastie ( http://pastie.caboo.se/1157 ). There's no name or attribution.. so great work stranger!

class CreditCard < ActiveRecord::Base
  belongs_to :legal_entity
  validates_numericality_of :number, :only_integer => true
  validates_presence_of :number, :expiration_date, :card_type
  validates_uniqueness_of :number, :scope => 'account_id', :message => 'matches a credit card already on your account'
  belongs_to :account

  def validate
    errors.add("number", "is not a #{card_type} or is invalid") unless number_valid? && number_matches_type?
  end

  def self.card_types
    { 'Visa'             => 'visa',
      'MasterCard'       => 'mastercard',
      'Discover'         => 'discover',
      'American Express' => 'amex' }
  end

  def readable_card_type
    (@@card_types ||= self.class.card_types.invert)[card_type]
  end

  def digits
    @digits ||= number.gsub(/[^0-9]/, '')
  end

  def last_digits
    digits.sub(/^([0-9]+)([0-9]{4})$/) { '*' * $1.length + $2 }
  end

  protected
  def number_valid?
    total = 0
    digits.reverse.scan(/(\d)(\d){0,1}/) do |ud,ad|
      (ad.to_i*2).to_s.each {|d| total = total + d.to_i} if ad
      total = total + ud.to_i
    end
    total % 10 != 0
  end

  def number_matches_type?
    digit_length = digits.length
    case card_type
    when 'visa'
      [13,16].include?(digit_length) and number[0,1] == "4"
    when 'mastercard'
      digit_length == 16 and ("51" .. "55").include?(number[0,2])
    when 'amex'
      digit_length == 15 and %w(34 37).include?(number[0,2])
    when 'discover'
      digit_length == 16 and number[0,4] == "6011"
    end
  end
end

Dynamic CSS stylesheets in Rails

Found here (with more info). Probably the best new Rails blog around at the moment.

class StylesheetsController < ApplicationController
  layout  nil
  session :off
  def rcss
    if rcss = params[:rcss]
      file_base = rcss.gsub(/.css$/i, '')
      file_path = "#{RAILS_ROOT}/app/views/stylesheets/#{file_base}.rcss"
      @color = '#f77' # example setting
      render(:file => file_path, :content_type => "text/css")
    else
      render(:nothing => true, :status => 404)
    end
  end
end

My default layout in Rails projects

Writing a new layout from scratch gets boring, so I have a generic / default layout to use and extend from.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/ DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title><%= @page_title %></title>
	<%= stylesheet_link_tag "main" %>
	<%= javascript_include_tag "prototype" %>
	<%= javascript_include_tag "scriptaculous" %>
	<%= javascript_include_tag "general" %>
	<!--[if lt IE 7.]>
	<script defer type="text/javascript" src="/javascripts/pngfix.js"></script>
	<![endif]-->
</head>

<body class="<%= @body_class %>">
	<div id="container">
			
	<%= @content_for_layout %>

	</div>
</body>
</html>


pngfix.js is available here.

Simplifying ActionMailer development in Ruby on Rails

Sick of writing almost the same thing over and over in your ActionMailer classes? Skip all that, and use something like this.

class Mailer < ActionMailer::Base

  helper ActionView::Helpers::UrlHelper

  def generic_mailer(options)
    @recipients = options[:recipients] || "me@privacy.net"
    @from = options[:from] || "me@privacy.net"
    @cc = options[:cc] || ""
    @bcc = options[:bcc] || ""
    @subject = options[:subject] || ""
    @body = options[:body] || {}
    @headers = options[:headers] || {}
    @charset = options[:charset] || "utf-8"
  end
  
  # Create placeholders for whichever e-mails you need to deal with.
  # Override mail elements where necessary
  
  def contact_us(options)
    self.generic_mailer(options)
  end

  ...

end


(If you have a configuration loaded into a constant, you could just replace the defaults above and use your app's defaults to make it all cleaner, of course)

And then from your controller you can do stuff like this:

Mailer.deliver_contact_us(
   :recipients => "x@x.com",
   :body => { 
               :name => params[:name],
               :phone => params[:phone],
               :email => params[:email],
               :message => params[:message]
             },
   :from => "y@y.com"
)

Using subdomain as account key in Ruby on Rails

Taken from here.

attr_writer :account
attr_reader :account
before_filter { |c| c.account = Account.find_by_subdomain(c.request.subdomains.first) }

Using sessions and caches only on certain actions in Rails

Stolen from Typo and found here. Typo is on an open licence so this should be okay.. :)

class ArticlesController < ApplicationController
  cached_pages = [:index, :read, :permalink, :category, 
    :find_by_date, :archives, :view_page, :tag]
  caches_page *cached_pages
  session :off, :only => cached_pages

  ...
end


Means you'll end up with less pointless sessions being stored..

Importing a Rails project to an SVN repository

svn import railsproject svn://whatever/railsproject/trunk


Then check out to a new location with:

svn co svn://whatever/railsproject/trunk railsproject


Then do all the housekeeping from the railsproject folder:

svn remove log/*
svn commit -m "Removed log files"
svn propset svn:ignore "*.log" log/
svn update log/
svn commit -m "Ignoring log files"
svn move config/database.yml config/database.example
svn propset svn:ignore "database.yml" config/
svn update config/
svn commit -m "Moved database file and ignoring future database.yml"


Mostly poached from http://wiki.rubyonrails.com/rails/pages/HowtoUseRailsWithSubversion
« Newer Snippets
Older Snippets »
Showing 1-10 of 34 total  RSS