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

« Newer Snippets
Older Snippets »
Showing 21-30 of 111 total

Javascript Rails-like inflector

I was using Ajax to do some DOM manipulation in a Rails app I was working on. None of what I was doing needed to involve a round trip to server, the only reason I hit the server at all was to take advantage of Rails' (well, ActiveSupport's) pluralize function. Also, this technique required an extra action that I decided to eliminate as I try to move to a more RESTful architecture.

The only part of ActiveSupport's Inflector class I implemented are the ones I needed. I implemented even fewer of Rails' Inflector-based functions.

Stick all this in a file, such as "inflector.js".
   1  /*
   2   * This script depends on no outside libraries.
   3   */
   4  
   5  Inflector = {
   6      /*
   7       * The order of all these lists has been reversed from the way 
   8       * ActiveSupport had them to keep the correct priority.
   9       */
  10      Inflections: {
  11          plural: [
  12              [/(quiz)$/i,               "$1zes"  ],
  13              [/^(ox)$/i,                "$1en"   ],
  14              [/([m|l])ouse$/i,          "$1ice"  ],
  15              [/(matr|vert|ind)ix|ex$/i, "$1ices" ],
  16              [/(x|ch|ss|sh)$/i,         "$1es"   ],
  17              [/([^aeiouy]|qu)y$/i,      "$1ies"  ],
  18              [/(hive)$/i,               "$1s"    ],
  19              [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"],
  20              [/sis$/i,                  "ses"    ],
  21              [/([ti])um$/i,             "$1a"    ],
  22              [/(buffal|tomat)o$/i,      "$1oes"  ],
  23              [/(bu)s$/i,                "$1ses"  ],
  24              [/(alias|status)$/i,       "$1es"   ],
  25              [/(octop|vir)us$/i,        "$1i"    ],
  26              [/(ax|test)is$/i,          "$1es"   ],
  27              [/s$/i,                    "s"      ],
  28              [/$/,                      "s"      ]
  29          ],
  30          singular: [
  31              [/(quiz)zes$/i,                                                    "$1"     ],
  32              [/(matr)ices$/i,                                                   "$1ix"   ],
  33              [/(vert|ind)ices$/i,                                               "$1ex"   ],
  34              [/^(ox)en/i,                                                       "$1"     ],
  35              [/(alias|status)es$/i,                                             "$1"     ],
  36              [/(octop|vir)i$/i,                                                 "$1us"   ],
  37              [/(cris|ax|test)es$/i,                                             "$1is"   ],
  38              [/(shoe)s$/i,                                                      "$1"     ],
  39              [/(o)es$/i,                                                        "$1"     ],
  40              [/(bus)es$/i,                                                      "$1"     ],
  41              [/([m|l])ice$/i,                                                   "$1ouse" ],
  42              [/(x|ch|ss|sh)es$/i,                                               "$1"     ],
  43              [/(m)ovies$/i,                                                     "$1ovie" ],
  44              [/(s)eries$/i,                                                     "$1eries"],
  45              [/([^aeiouy]|qu)ies$/i,                                            "$1y"    ],
  46              [/([lr])ves$/i,                                                    "$1f"    ],
  47              [/(tive)s$/i,                                                      "$1"     ],
  48              [/(hive)s$/i,                                                      "$1"     ],
  49              [/([^f])ves$/i,                                                    "$1fe"   ],
  50              [/(^analy)ses$/i,                                                  "$1sis"  ],
  51              [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"],
  52              [/([ti])a$/i,                                                      "$1um"   ],
  53              [/(n)ews$/i,                                                       "$1ews"  ],
  54              [/s$/i,                                                            ""       ]
  55          ],
  56          irregular: [
  57              ['move',   'moves'   ],
  58              ['sex',    'sexes'   ],
  59              ['child',  'children'],
  60              ['man',    'men'     ],
  61              ['person', 'people'  ]
  62          ],
  63          uncountable: [
  64              "sheep",
  65              "fish",
  66              "series",
  67              "species",
  68              "money",
  69              "rice",
  70              "information",
  71              "equipment"
  72          ]
  73      },
  74      ordinalize: function(number) {
  75          if (11 <= parseInt(number) % 100 && parseInt(number) % 100 <= 13) {
  76              return number + "th";
  77          } else {
  78              switch (parseInt(number) % 10) {
  79                  case  1: return number + "st";
  80                  case  2: return number + "nd";
  81                  case  3: return number + "rd";
  82                  default: return number + "th";
  83              }
  84          }
  85      },
  86      pluralize: function(word) {
  87          for (var i = 0; i < Inflector.Inflections.uncountable.length; i++) {
  88              var uncountable = Inflector.Inflections.uncountable[i];
  89              if (word.toLowerCase == uncountable) {
  90                  return uncountable;
  91              }
  92          }
  93          for (var i = 0; i < Inflector.Inflections.irregular.length; i++) {
  94              var singular = Inflector.Inflections.irregular[i][0];
  95              var plural   = Inflector.Inflections.irregular[i][1];
  96              if ((word.toLowerCase == singular) || (word == plural)) {
  97                  return plural;
  98              }
  99          }
 100          for (var i = 0; i < Inflector.Inflections.plural.length; i++) {
 101              var regex          = Inflector.Inflections.plural[i][0];
 102              var replace_string = Inflector.Inflections.plural[i][1];
 103              if (regex.test(word)) {
 104                  return word.replace(regex, replace_string);
 105              }
 106          }
 107      }
 108  }
 109  
 110  function ordinalize(number) {
 111      return Inflector.ordinalize(number);
 112  }
 113  
 114  /*
 115   * Javascript doesn't have optional parameters or overloading so I had to use
 116   * the ever popular pseudo options hash object technique.
 117   * required properties:
 118   *     count    Number of objects to pluralize
 119   *     singular Singular noun for the objects
 120   * optional property:
 121   *     plural   Plural (probably irregular) noun for the objects
 122   * examples:
 123   *      pluralize({ count: total_count, singular: "Issue" })
 124   *      pluralize({ count: total_count, singular: "Goose", plural: "Geese" })
 125   */
 126  function pluralize(options) {
 127      return options.count + " " + (1 == parseInt(options.count) ?
 128          options.singular :
 129          options.plural || Inflector.pluralize(options.singular));
 130  }

Manually Pulling Data From MySQL in Rails

Sometimes you just have to do it yourself, like when you have relationships between different databases.
Here I wanted to retrieve an array of site_ids:

   1  
   2      result = ActiveRecord::Base.connection.execute("SELECT * FROM sites_users WHERE user_id ='#{self.id}'")
   3      rows = []
   4      result.each_hash {|h| rows << h['site_id'].to_i }
   5      return rows


UPDATE: ( An easier, better way)

   1  
   2      rows = ActiveRecord::Base.connection.select_values("SELECT site_id FROM sites_users WHERE user_id ='#{self.id}'")
   3      return rows.map {|el| el.to_i }


There is also:

select_one(sql, name = nil)
select_value(sql, name = nil)
select_all(sql, name = nil)

Clone dev DB schema to test DB in Rails

Ruby on Rails

Command to clone the 'dev' DB to 'test' DB
   1  
   2  rake clone_structure_to_test

*note* clones the structure/schema but NOT the content in the tables.

Filtering based on a has_and_belongs_to_many association

To create an indexed view of either all of the items (in a normal index view), or filtered based on an association, you can do the following. For example, if you have a many to many relationship between "users" and "tags", and you wish an index view of users filtered on whether they contain a particular tag, you can do the following:

In the tag index view:
   1  
   2  <h1>Listing tags</h1>
   3  
   4  <table>
   5    <tr>
   6      <th>Name</th>
   7    </tr>
   8  
   9  <% for tag in @tags %>
  10    <tr>
  11      <td><%=h tag.name %></td>
  12      <td><%= link_to 'Users', user_path(:tag_id=>tag) %></td>
  13      <td><%= link_to 'Show', tag_path(tag) %></td>
  14      <td><%= link_to 'Edit', edit_tag_path(tag) %></td>
  15      <td><%= link_to 'Destroy', tag_path(tag), :confirm => 'Are you sure?', :method => :delete %></td>
  16    </tr>
  17    <% end %>
  18  </table>
  19  <br />
  20  <%= link_to 'New tag', new_tag_path %>


Note that
   1  user_path(:tag_id=>tag)
translates to
   1  <a href="/users?tag_id=1">Users</a>
.

In the controller for users, modify the index and change the standard @users=User.find(:all) to

   1  
   2      @tag=Tag.find(params[:tag_id]) if params[:tag_id]
   3      @users = @tag.users || throw rescue User.find(:all)


The
   1  throw rescue
was because the @tag.users could throw an exception as well as having a nil value, and this is DRYer than coding it as
   1  
   2      @users = @tag.users || User.find(:all) rescue User.find(:all)


Full details at Displaying a subset of items from an association.

Capistrano : apply local patches when deploying from an external source code repository

I've submitted patches to a couple rails apps, and want to run off of their SCM's trunk code, but with my local patches applied. These Capistrano tasks will take any files matching
patches/*.diff
in your local directory, and apply them before restarting your app.

   1  
   2  task :after_setup do
   3    patches_setup
   4  end
   5  
   6  task :after_update_code do
   7    send_and_apply_patches
   8  end
   9  
  10  task :patches_setup do
  11    run "mkdir -p #{deploy_to}/#{shared_dir}/patches" 
  12  end
  13  
  14  task :send_and_apply_patches do
  15    Dir[File.join(File.dirname(__FILE__), '../patches/*.diff')].sort.each do |patch|
  16      puts "sending #{File.basename(patch)}"
  17      put(File.read(patch),
  18         "#{deploy_to}/#{shared_dir}/patches/#{File.basename(patch)}",
  19         :mode => 0777)
  20      puts "applying #{File.basename(patch)}"
  21      run "cd #{release_path}; patch -p0 < #{deploy_to}/#{shared_dir}/patches/#{File.basename(patch)}"
  22    end
  23  end

Javascript code to set Rails date_select to today.

If you are using date_select in rails here is a little bit of javascript so that at the side of the fields the user can click a link that will automatically set the fields to todays date.

Updated: Now works on rails 1.2, as date_select now finally has ids
   1  
   2  # put is app_root/public/javascript/application.js
   3  
   4  function set_today(model, atrib)
   5  {
   6      t3 = document.getElementById(model + '_' + atrib + '_3i');
   7      var dt = new Date(); 
   8      t3.selectedIndex = dt.getDate();
   9  	
  10      t2 = document.getElementById(model + '_' + atrib + '_2i')
  11      t2.selectedIndex = dt.getMonth() + 1;
  12      
  13      t1 = document.getElementById(model + '_' + atrib + '_1i')
  14  
  15      for (i = 0; i < t1.length; i++)
  16  	       {
  17  	           if (t1.options[i].text == dt.getFullYear())
  18  	           {
  19  	               t1.selectedIndex = i;
  20  	          }
  21      } 
  22  }





To call this method say in a link use this in your rhtml

   1  
   2  <a href="javascript: set_today('model_name', 'column_name');">today?</a>

Helper to Display Rails Flash Messages

A simple code snippet for displaying your flash[:warning] = "Warning Message" messages in rails.

   1  
   2  def flash_helper
   3    
   4      f_names = [:notice, :warning, :message]
   5      fl = ''
   6      
   7      for name in f_names
   8        if flash[name]
   9          fl = fl + "<div class=\"notice\" id=\"#{name}\">#{flash[name]}</div>"
  10        end
  11        flash[name] = nil;
  12      end
  13      return fl
  14    end

Getting the _session_id from SWFUpload (Flash 8 multiple file uploader)

It appears that Ruby's CGI::Session class will not use the _session_id in the query string when the Request is a POST.

Normally, a POST-type request occurs when a form is submitted to the server (e.g. a Rails application). In this scenario, there is an easy workaround since we can send the _session_id as a hidden field.

With Flash 8, however, there is no way to add a 'hidden field' to the multi-part form data, thus Rails will fail to recognize the _session_id in the query string portion of our request.

Here is a hackish work-around:

   1  
   2  # The following code is a work-around for the
   3  # Flash 8 bug that prevents our multiple file uploader
   4  # from sending the _session_id.  Here, we hack the
   5  # Session#initialize method and force the session_id
   6  # to load from the query string via the request uri. 
   7  # (Tested on Lighttpd)
   8  
   9  class CGI::Session
  10    alias original_initialize initialize
  11    def initialize(request, option = {})
  12      session_key = option['session_key'] || '_session_id'
  13      option['session_id'] =
  14        request.env_table["REQUEST_URI"][0..-1].
  15        scan(/#{session_key}=(.*?)(&.*?)*$/).
  16        flatten.first
  17      original_initialize(request, option)
  18    end
  19  end

Extending acts_as_taggable to take scope into account

The acts_as_taggable plugin is great and so useful. But it discards scope, and it doesn't work like any other model attribute in your controller views [using normal @model.update(params[:model]) calls].

I have changed it to:
* add an alias tag_list= for tag_with (found in the "rails wiki":http://wiki.rubyonrails.com/rails/pages/ActsAsTaggablePluginHowto),
* updated find_tagged_with and count_tagged_with to use scope (after reading an article from Jamis on "ActiveRecord::Base.find":http://weblog.jamisbuck.org/2006/11/20/under-the-hood-activerecord-base-find-part-2)

Scope is used when doing this for instance:

   1  
   2    Message.with_scope :find => {:conditions => ["project_id = ?", @project]} do
   3      @messages = Message.find_tagged_with(tag.name)
   4    end


Then only the messages tagged with tag.name that belong to project @project.


*acts_as_taggable.rb*

   1  
   2  module ActiveRecord
   3    module Acts #:nodoc:
   4      module Taggable #:nodoc:
   5        def self.included(base)
   6          base.extend(ClassMethods)  
   7        end
   8        
   9        module ClassMethods
  10          def acts_as_taggable(options = {})
  11            write_inheritable_attribute(:acts_as_taggable_options, {
  12              :taggable_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s,
  13              :from => options[:from]
  14            })
  15            
  16            class_inheritable_reader :acts_as_taggable_options
  17  
  18            has_many :taggings, :as => :taggable, :dependent => true
  19            has_many :tags, :through => :taggings
  20  
  21            include ActiveRecord::Acts::Taggable::InstanceMethods
  22            extend ActiveRecord::Acts::Taggable::SingletonMethods          
  23          end
  24        end
  25        
  26        module SingletonMethods
  27          def find_tagged_with(list)
  28            tagged_with list
  29          end
  30  
  31          def count_tagged_with(list)
  32            tagged_with list, :count
  33          end
  34  
  35          # DRY sql query and handle scope
  36          protected
  37          def tagged_with(list, type = :find)
  38            if type == :count
  39              sql = "SELECT COUNT(DISTINCT #{table_name}.#{primary_key}) AS cnt "
  40            else
  41              sql = "SELECT DISTINCT #{table_name}.* "
  42            end
  43            sql << "FROM #{table_name}, tags, taggings "
  44  
  45            conditions = [
  46              "#{table_name}.#{primary_key} = taggings.taggable_id " +
  47              "AND taggings.taggable_type = ? " +
  48              "AND taggings.tag_id = tags.id AND tags.name IN (?) ",
  49              acts_as_taggable_options[:taggable_type], list
  50              ]
  51            add_conditions!(sql, conditions)
  52  
  53            result = find_by_sql(sql)
  54            (type == :count) ? result.first.cnt.to_i : result
  55          end
  56  
  57        end
  58        
  59        module InstanceMethods
  60          def tag_with(list)
  61            Tag.transaction do
  62              taggings.destroy_all
  63  
  64              Tag.parse(list).each do |name|
  65                if acts_as_taggable_options[:from]
  66                  send(acts_as_taggable_options[:from]).tags.find_or_create_by_name(name).on(self)
  67                else
  68                  Tag.find_or_create_by_name(name).on(self)
  69                end
  70              end
  71            end
  72          end
  73  
  74          # allow using active record update_attributes() and others by using tag_list to set
  75          # and read the tag list
  76          alias tag_list= tag_with
  77  
  78          def tag_list
  79            tags.collect { |tag| tag.name.include?(" ") ? "'#{tag.name}'" : tag.name }.join(" ")
  80          end
  81        end
  82      end
  83    end
  84  end

XML attributes to database columns

I recently needed to update a database with the contents of an XML file under a controlled environment (details at Blackrat's Blog) and came up with this.

With an XML input file of the following format
   1  
   2  <tags>
   3    <tag name='test' desc='Test Description' other='Other Item' />
   4    <tag name='test2' desc='2nd Test Description' other='Another Item' />
   5  </tags>


and a database which contains identical columns name,desc,other (or a superset of the tags) you can use the follow snippet to populate it.

View [import_xml.rhtml]
   1  
   2  <h1>Import XML</h1>
   3  
   4  <%= form_tag({ :action => 'import_xml'}, { :multipart => true }) %>
   5  <%= file_field 'document', 'file' %>
   6  <%= submit_tag 'Import' %>
   7  <%= end_form_tag %>


Controller [names_controller.rb]
   1  
   2  def import_xml
   3    require 'rexml/document'
   4    file=params[:document][:file]
   5    doc=REXML::Document.new(file.read)
   6    doc.root.each_element('//tag') do |tag|
   7      @name = Name.new
   8      @name.update_attributes(tag.attributes)
   9    end
  10    redirect_to :action => 'list'
  11  end

« Newer Snippets
Older Snippets »
Showing 21-30 of 111 total