DRY RAILS database.yml config file

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

Update: Matt says that Typo uses this scheme for their database.yml, which is likely where I first saw it. Jonathan mentions that this is also included in Rails Recipes, which I have to admit I’ve owned since the day it came out as a betabook but never actually looked at. Thanks, guys!

While paging through NetNewsWire this afternoon, I came across James Duncan Davidson’s article Conditional Rails Database Configuration. “Damn”, thought I, “ERb in the database.yml is a neat trick, but it’s so ugly!”

That reminded me of a little trick I’ve been using for as long as I can remember. I can’t take credit for this technique as I learned it from someone else… I just don’t remember who. Anyway, it goes a little something like this:

1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17

18

login: &login
  adapter: mysql
  username: username
  password: password

  host: mysql.example.com

development:
  <<: *login
  database: app_dev

test:
  <<: *login

  database: app_test

production:
  <<: *login
  database: app_prod

That’s a pretty standard Rails database.yml, all DRYed out. Like I said, I’ve been doing this forever but I rarely see it in other apps.

To extend on James’ post, here’s what his example would look like if you follow this technique:

1
2
3
4

5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
30
31

32
33

common: &common
  adapter: mysql

dev: &dev

  <<: *common
  username: root
<% if File.exist? "/opt/local/var/run/mysql5/mysqld.sock" %>
  socket: /opt/local/var/run/mysql5/mysqld.sock
<% elsif File.exist? "/tmp/mysql.sock" %>
  socket: /tmp/mysql.sock
<% end %>


development:
  <<: *dev
  database: birdy

test:
  <<: *dev
  database: birdy_test


production:
  <<: *common
  host: 10.0.1.24
<% if `uname -n`.strip == "staging" %>
  database: birdy_stage
  username: birdy_stage

  password: somethingsecret
<% else %>
  database: birdy
  username: birdy
  password: somethingelsethatissecret
<% end %>

Okay okay, it’s ugly for sure. But it’s functional and repetition has been removed where possible, making it less ugly than before. Of course you could get even trickier and tweak with the conditionals in the Production environment, but then you start getting into spaghetti ERb in your database.yml, which has got to be some sort of sin.

So there you go. I’d dearly love to see this method gain more popularity as it’s so much cleaner. I can’t be the only one whose development environment is close enough to his production environment to let this work!

Confidential to James. I am not a real blogger yet because of my schedule, I just keep the post that will be helpful to me, in my blog.

Improved in_place_select_editor

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

The in_place_select_editor method assumes that you want to display the exact item being edited. That isn’t always the case. You might want to display a related attribute. The following modifies in_place_select_editor_field by allowing it to take a display parameter (third parameter), which is then passed to to_content_tag_display (also modified)

module ApplicationHelper

  def in_place_select_editor(field_id, options = {})

    function =  "new Ajax.InPlaceSelectEditor("
    function << "'#{field_id}', "

    function << "'#{url_for(options[:url])}'"
    function << (', ' + options_for_javascript(

       {
         'selectOptionsHTML' =>
                %('#{escape_javascript(options[:select_options].gsub(/n/, ""))}')

       }
       )
    ) if options[:select_options]
    function << ')'

    javascript_tag(function)
  end

  def in_place_select_editor_field(object, method, display, tag_options = {},
                                   in_place_editor_options = {})

    tag = ::ActionView::Helpers::InstanceTag.new(object, method, self)

    tag_options = { :tag => "span",
                    :id => "#{object}_#{method}_#{tag.object.id}_in_place_editor",
                   :class => "in_place_editor_field"}.merge!(tag_options)

    in_place_editor_options[:url] =
       in_place_editor_options[:url] ||
       url_for({ :action => "set_#{object}_#{method}", :id => tag.object.id })

    tag.to_content_tag_display(tag_options.delete(:tag), display, tag_options) +

    in_place_select_editor(tag_options[:id], in_place_editor_options)
  end

end

module ActionView
module Helpers

    class InstanceTag #:nodoc:
      include Helpers::TagHelper

      def to_content_tag_display(tag_name, display, options = {})

        content_tag(tag_name, display, options)
      end

    end

end
end

This permits (example), where Job.vendor_name(@job) (a custom method) is displayed.

            <%= in_place_select_editor_field(
             :job,
             :vendor_id,
             Job.vendor_name(@job),
             {},
             :select_options => options_from_collection_for_select(@vendors, 'id', 'name', @job.vendor_id)) %>

you could also use this to display an icon to click on to display the drop-down box by passing an image_tag as the third parameter.

MemCacheStore and FileStore in Ruby on Rails

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

This allows to expire cached fragments by ttl. Example usage (in views):

<% cache("name", :ttl => 7.days) do %>

  ... some database-heavy stuff ...
<% end %>

Put the following in environment.rb or in lib/.

class ActionController::Caching::Fragments::MemCacheStore
  def write(name, value, options=nil)

    if options.is_a?(Hash) && options.has_key?(:ttl)

      ttl = options[:ttl]
    else
      ttl = 0

    end
    @data.set(name, value, ttl)

  end
end

module ActionView::Helpers::CacheHelper
  def cache(name = {}, options = nil, &block)

    @controller.cache_erb_fragment(block, name, options)
  end

end

class ActionController::Caching::Fragments::UnthreadedFileStore
  def read(name, options = nil)
    if options.is_a?(Hash) && options.has_key?(:ttl)

      ttl = options[:ttl]
    else
      ttl = 0

    end

    fn = real_file_path(name)

    # if cache expired act as if file doesn't exist

    return if ttl > 0 && File.exists?(fn) && (File.mtime(fn) < (Time.now - ttl))

    File.open(fn, 'rb') { |f| f.read } rescue nil

  end
end

RJS with toggle_slide if not visible only

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

RJS is very powerful. here is a small code snippet that shows how to do a toggle on a div if NOT visible. If the div is visible, it just exchange it. Here is my rhtml code:

    <div style="height: 30px">
        <div style="float: left; padding: 0 0 0 180px">

            <%= link_to_remote("test_visibility" ,
                :with => "'is_visible=' + Element.visible('list_div')",
                :loading => "Element.show('getting_results')",

                :complete => "Element.hide('getting_results')",
                :failure => "alert('An error occured, please email us directly!')",

                :url => { :action => 'one_action' }) %>

        </div>
        <div id="getting_results" style="float: left; padding: 3px 0 0 30px; display: none;">
            <%= image_tag "ajax-loader.gif", :class => "image", :alt => "loading..." %>

        </div>
    </div>

    <div id="list_div" style="display: none;" >
    </div>

And in my controller, I have the following code:

def one_action

      render :update do | page |
        page.replace_html 'list_div', :partial => 'one_partial'

        if params['is_visible'] == 'false'
          page.visual_effect :toggle_slide, 'list_div', :duration => 2

        end
      end
end

How it works?

Element.visible('list_div')

is a prototype function that returns false if the element is not visible and true if it is. In the above case, we have the orginial visibility of the div to be “display: none”. Thus the first time the action is called, the Ajax call will send the parameter false to the action. This will make the div appear. For subsequent requests, the value of visibility will be true, thus only replacing the div.

Passing parameters into before filter

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

application.rb

class ApplicationController < ActionController::Base

  def hello(name)

   "Hello #{name}"  end

end

users_controllers.rb

class UsersController < ApplicationController

before_filter :o nly => :index do |u|
u.hello(‘Master‘)

end

end

SQL Transaction in Rails

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

def fetch_value
sql = ActiveRecord::Base.connection();
sql.execute SET autocommit=0“;

sql.begin_db_transaction
id, value =
sql.execute(“SELECT id, value FROM sometable WHERE used=0 LIMIT 1 FOR UPDATE“).fetch_row;

sql.update UPDATE sometable SET used=1 WHERE id=#{id}“;
sql.commit_db_transaction

value;

end

Javascript code to set Rails date_select to today.

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

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

# put is app_root/public/javascript/application.jsfunction set_today(model, atrib){t3 = document.getElementById(model + '_' + atrib + '_3i');

var dt = new Date();t3.selectedIndex = dt.getDate();t2 = document.getElementById(model + '_' + atrib + '_2i')

t2.selectedIndex = dt.getMonth() + 1;t1 = document.getElementById(model + '_' + atrib + '_1i')

for (i = 0; i < t1.length; i++){

      if (t1.options[i].text == dt.getFullYear())     {

            t1.selectedIndex = i;     }

}}

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

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

Seesaw: An Improved Restart System for Mongrel

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

Seesaw2

Most Rails developers will be familiar with Zed Shaw’s Mongrel, a great HTTP library used by most Rails developers to either test or deploy their applications (it’s also pretty great for building your own basic HTTP handlers too, but I digress).

Sometimes when restarting applications after code updates, some requests can be “lost” in the whole process, particularly in high-traffic environments. Seesaw, developed by Max Muermann and Matt Allen, however, resolves this problem by restarting your mongrel processes one by one so that availability is ensured. Seesaw is available as a gem (gem install seesaw), although this blog post is essential reading to learn about integration with Nginx and Apache.

Directory Listing in Ruby On Rails

Posted by Bhushan Ahire | Posted in Rails | Posted on 03-09-2007

0

The code displays all the subdirectories and files listed in the the main directory, and also displays these items as a link so that the following subdirectories can become the directories and diaplay the corresponding elements

IN CONTROLLER...............

DEF listing

   if (params[:dir] !=nil)      @path   = params[:path]+"/"+params[:dir]

   else      @path ="D:/Folder_name"   end

      @dirEntries = Dir.entries(@path)

      @dirEntries.reject! { |filename| filename.starts_with? '.'}

end

IN VIEWS.........<%= javascript_include_tag :defaults %>

<% for dir in @dirEntries %> <%= link_to "#{dir}", :action => 'listing', :path => @path, :dir => dir %><br/>

<% end %>