Archive for June, 2008

Simple search form with Ruby on Rails

To create a simple search form see Ryan’s Episode 37.

# in your model
def self.search(search)
    if search
      find(:all, :conditions => ["first_name LIKE ? or middle_name LIKE ? or last_name LIKE ? or body LIKE ?", "%#{search}%", "%#{search}%", "%#{search}%", "%#{search}%"], :order => 'service_date DESC')
    else
      find(:all, :order => 'service_date DESC')
    end
end
# in your controller
def index
    @records = Record.search(params[:search])
end
# in your view
<% form_tag admin_obituaries_path, :method => 'get' do %>


  <%= text_field_tag :search, params[:search] %>
  <%= submit_tag "Search", :name => nil %>
 

<% end %>

Virtual Attribute - joining first_name and last_name into full_name with Rails

To join first_name and last_name into a virtual attribute full_name using Ruby on Rails check out Ryan’s Episode 16.

# This is your model
class User < ActiveRecord::Base
  def full_name
    [first_name, last_name].join(' ')
  end

  def full_name=(name)
    split = name.split(' ', 2)
    self.first_name = split.first
    self.last_name = split.last

  end
end

You can expand on that to do things like this:

  def full_name
    [first_name, middle_name, last_name].join(' ')
  end

  def full_name_backwards
    [last_name, [first_name, middle_name].join(' ')].join(', ')
  end

exception_notification plugin install

The exception_notification plugin is a great tool to debug your deployed application. You get an email when an error occurs.

To download (it is now on get): http://github.com/rails/exception_notification/tree/master/README

script/plugin install git://github.com/rails/exception_notification.git

Some tutorials to help out:
- http://internetducttape.com/2008/02/06/rails-guide-exception-notifier-plugin/
- http://soakedandsoaped.com/articles/read/exception-notifier-ruby-on-rails-plugin

AJAX delete button, link_to_remote with rails

To change your rails delete button into an ajax one. Do the following (this example is for images, but would apply to anything else with some tweaking):

The action

# DELETE /images/1
  # DELETE /images/1.xml
  def destroy
    @image = Image.find(params[:id])
    @image.destroy

    respond_to do |format|
      format.html { redirect_to admin_images_url }
      format.xml  { head :ok }
      format.js do
        render :update do |page|
          page.remove "image_#{@image.id}"
        end
      end
    end
  end

The view

<%= image_tag( image.public_filename(), :height => 70 ) %> <%= link_to 'view', admin_image_path(image) %> | <%= link_to_remote 'delete', :url => admin_image_path(image), :confirm => 'Are you sure?', :method => :delete %> <%#= link_to_remote "delete", :update => "images", :url => { :action => "destroy", :id => image.id }%>

Fixing NULL value problem in rails

To fix the NULL value problem in rails, you actually need to fix your mysql. It’s a mysql issue.

For your migration, do something like this (making sure to include :null => false)

class AddParentIdToPages < ActiveRecord::Migration
  def self.up
    add_column :pages, :parent_id, :integer, :default => 0, :null => false
  end

  def self.down
    remove_column :pages, :parent_id
  end
end

Normalizing data through the model before pushing to the database

Put this in your model

  before_validation :normalize
  def normalize
    symbol.upcase!
    #other modifications here
  end

Normalizing data in the model

Select drop down box for page parent (collection_select & acts_as_tree)

To create a Page parent drop down box similar to the one on wordpress.com in order to create subpages and subpages of subpages the following should help you out. (Go to #2 for the goods)

1. First the basics, a select list (just so you know what is basically going on):

<%= f.label :parent_id, 'Parent page' %>:
<%= collection_select(:page, :parent_id, Page.find(:all, :conditions => ["parent_id = ?", 0], :order => :position), :id, :title, {:include_blank => true}) %>

2. Use acts_as_tree and some helpers to do a recursive look down the pages table (this assumes you have a parent_id field in your pages. 0 or Null for highest level and then a sub page would have the id of the its parent.
.
UPDATE: Great pastie on render_tree_select. Thank you LeeH.
UPDATE 2!!!: LeeH’s code has some html generation errors for the select box. I fixed it and also added current selection ability with selected=”selected” and exclusion

Use the code below (or my pastie for render_tree_select:

    def render_tree_select(pages, name, control_id, control_name, current_selection, exclusion, blank_record)
      ret = ''
      ret += "


"
    end

    def recurse_tree(page, depth, name, current_selection, exclusion)
      depth = depth + 1
      level = "- " * depth
      ret = ''
      if page.children.size > 0
        page.children.each { |subpage|
          if subpage.id != exclusion
          if subpage.children.size > 0
              ret += ''
           end
         end
         }
         ret += ''
      end
    end

And in your view:

<%= render_tree_select(Page.find(:all, :conditions => ["parent_id = ? and id != ?", 0, @page.id], :order => :position), :title, 'page_parent_id', 'page[parent_id]', @page.parent_id, @page.id, 'Main page (no parent)') %>


NOTE: Everything below here is a little old - somewhat useful, but the pastie and code above is much better.

Rails wiki to the rescue

I put this in a helper I named FormHelper

def render_tree_select(pages, name)
  ret = ''
  ret += "


"
end

def recurse_tree(page, depth, name)
        depth = depth + 1
        level = "- " * depth
        ret = ''
        if page.children.size > 0
          page.children.each { |subpage|
            if subpage.children.size > 0
              ret += ''
            else
              ret += ''
            end
            }
          ret += ''
        end
end

Then put the following in your view:

<%= render_tree_select(Page.find(:all), :title) %>

Other stuff:
- http://pastie.org/213753

Using MarsEdit now as my desktop blog publisher

I gave Blogo a shot and liked it for a while, but then I tried MarsEdit. I prefer MarsEdit’s interface - more whitespace.

Though I would like the ability to auto-resize images on upload. That would be very helpful.

Picture 1.png

Ajaxy image uploading with attachment_fu - undefined method ‘content type’ error

While Ajax commenting worked great in my last post, it did not apply to ajax image uploading. This is apparently because there is a security restriction with javascript preventing access to the file system. I was getting the following error in my development server (using attachment_fu to process the images).

Processing ImagesController#create (for 127.0.0.1 at 2008-06-10 22:55:13) [POST]
  Session ID: BAh7CToMY3NyZl9pZCIlZGJhYTNjYTExZWE2MzdjMWQ1MGE2YjUwOWEzNjVh%0AMjA6DnJldHVybl90bzA6DHVzZXJfaWRpBiIKZmxhc2hJQzonQWN0aW9uQ29u%0AdHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--a5f5fe97ec5e10d7a380e09ed1b0affc1f8030ce
  Parameters: {"commit"=>"Create", "authenticity_token"=>"779890648cc4b51c83eea32eb9f184534d171083", "action"=>"create", "controller"=>"admin/images", "image"=>{"uploaded_data"=>"1313883603_7dc8ef882f_o.jpg"}}
  User Columns (0.003101)   SHOW FIELDS FROM `users`
  User Load (0.001356)   SELECT * FROM `users` WHERE (`users`.`id` = 1) LIMIT 1
  Image Columns (0.002243)   SHOW FIELDS FROM `images`

NoMethodError (undefined method `content_type' for "1313883603_7dc8ef882f_o.jpg":String):
    /vendor/plugins/attachment_fu/lib/technoweenie/attachment_fu.rb:294:in `uploaded_data='

It should look like this:

Processing ImagesController#create (for 127.0.0.1 at 2008-06-10 23:02:07) [POST]
  Session ID: BAh7CToMY3NyZl9pZCIlZGJhYTNjYTExZWE2MzdjMWQ1MGE2YjUwOWEzNjVh%0AMjA6DnJldHVybl90bzA6DHVzZXJfaWRpBiIKZmxhc2hJQzonQWN0aW9uQ29u%0AdHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA%3D%3D--a5f5fe97ec5e10d7a380e09ed1b0affc1f8030ce
  Parameters: {"commit"=>"Create", "authenticity_token"=>"779890648cc4b51c83eea32eb9f184534d171083", "action"=>"create", "controller"=>"admin/images", "image"=>{"uploaded_data"=>#}}
  User Columns (0.003132)   SHOW FIELDS FROM `users`
  User Load (0.001419)   SELECT * FROM `users` WHERE (`users`.`id` = 1) LIMIT 1

User this solution:
It involves repsonds_to_parent and using iframes.

However, make sure to change the following…

<% form_for(:asset, :url =>formatted_assets_path(:format => 'js'), :html => { :multipart => true, :target => 'upload_frame'}) do |form| %>

to…

<% form_for(:asset, :url => assets_path + ".js", :html => { :multipart => true, :target => 'upload_frame'}) do |form| %>

That should do the trick.

Alternative links/solutions:
Another helpful link

The responds_to_parent plugin

Ajaxy commenting with Rails and RJS templates in Rails 2.0

1. Take a look at Ryan’s Episode 43
2. Make sure to change create.rjs to create.js.rjs for rails 2.0 (this was helpful)