Rails / In-place editing

From WhyNotWiki
Jump to: navigation, search

Contents

in_place_editor/in_place_editor_field helper

http://api.rubyonrails.org/classes/ActionView/Helpers/JavaScriptMacrosHelper.html#M000569

This is just a wrapper for scriptaculous's Ajax.InPlaceEditor

http://fora.pragprog.com/rails-recipes/discuss-the-book/post/57. Retrieved on 2007-05-11 11:18.


Michael,March 10 (06:52PM)

I have a model say User with a: validates_length_of :zip, :minimum => 5 if I do: in_place_edit_for :user, :zip it updates the :zip, but it doesn’t run the validation. I can put whatever I want in the field and it will save.

...

Daniel Klein,April 08 (01:53PM)

Michael’s post covers most of it. I’d add that sending back an alert to the user would be more useful. Define the editor this way:

in_place_editor_field ‘custom_field’, ‘name’, {}, :script => true

And then in the controller, use RJS to evaluate:

def set_custom_field_name
  @i      = CustomField.find(params[:id])
  old     = @i.name
  @i.name = params[:value]
end

[which controller action??]

if @i.save
  render :update do |page|
    page.replace_html( "custom_field_name_#{params[:id]}_in_place_editor", 
                       @i.send(:name) )
  end 
else
  render :update do |page| 
    page.replace_html( "custom_field_name_#{params[:id]}_in_place_editor", 
                       old )
    page.call( "alert",
           "Sorry: you cannot have a field with the same name as another")
  end
end

...

How to make it do validation

Josh (December 20, 2005 at 8:40 am). Ajax the Great (http://shnoo.gr/articles/2005/12/20/ajax-the-great). Retrieved on 2007-05-11 11:18.


... But that’s about as far as you can go. Matias Pelenur points out (in the notes) that in_place_edit_for doesn’t validate nor sanitize the input from the user, which is not a good thing. He recommends defining your own actions instead:

def set_product_name
  @product = Product.find(params[:id])
  previous_name = @product.name
  @product.name = params[:value]
  @product.name = previous_name unless @product.save
  render :text => @product.name
end

http://wiki.rubyonrails.org/rails/pages/HowToValidateWithAjaxInPlaceEditor HowToValidateWithAjaxInPlaceEditor in Ruby on Rails

How to use it with Textile

Josh (December 20, 2005 at 8:40 am). Ajax the Great (http://shnoo.gr/articles/2005/12/20/ajax-the-great). Retrieved on 2007-05-11 11:18.


You want to allow the blog author to click on his post and edit it in-place. When the article field turns into a textarea for editing, you want the text to revert to its textile syntax, not the final html. ...


Bug preventing use of namespaced models

http://dev.rubyonrails.org/ticket/8475 #8475 ([PATCH] in_place_editor_field doesn't work for namespaced models) - Rails Trac - Trac



In-place editing for drop-down select boxes (rather than text boxes) in_place_collection_editor_field helper

Daniel Klein (April 08 (06:49PM)). When Your In-Place Editor Needs a Drop-Down (http://fora.pragprog.com/rails-recipes/write-your-own/post/223). Retrieved on 2007-05-11 11:18.


...

<%= in_place_collection_editor_field 'custom_field', 'field_type', 
                           FieldType.find_all.collect{|x| [x.name,x.id]} %>

The x.name is the plaintext description, to be displayed to the user, while the x.id is the internal id. Given that the selected object id will be passed to the controller, along with the id of the object to process, the controller is simply defined as:

def set_custom_field_field_type
  @i = CustomField.find(params[:id])
  f  = FieldType.find(params[:value])
  @i.update_attribute( :field_type, f )
  render :text => f.name
end

#46627 - Pastie (http://pastie.caboo.se/46627). Retrieved on 2007-05-11 11:18.


def in_place_collection_editor_field(object,method,container, tag_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)
    url = url_for( :action => "set_#{object}_#{method}", :id => tag.object.id )
    collection = container.inject([]) do |options, element|
      options << "[ '#{escape_javascript(element.last.to_s)}', '#{escape_javascript(element.first.to_s)}']" 
    end
    function =  "new Ajax.InPlaceCollectionEditor("
    function << "'#{object}_#{method}_#{tag.object.id}_in_place_editor',"
    function << "'#{url}',"
    function << "{collection: [#{collection.join(',')}], id: '#{object}_#{method}'});"
    tag.to_content_tag(tag_options.delete(:tag), tag_options) + javascript_tag(function)
end


editable_content helper

This is just a wrapper for scriptaculous's Ajax.InPlaceEditor.

This provides more flexibility (perhaps more than you need) than in_place_editor_field.

Coda Hale (2006-01-14). A Rails HOWTO: Simplify In-Place Editing with Script.aculo.us (http://blog.codahale.com/2006/01/14/a-rails-howto-simplify-in-place-editing-with-scriptaculous/). Retrieved on 2007-05-11 11:18.


[I modified this sligthly. Renamed :ajax to :in_place_editor so that one wouldn't get it confused with ajaxOptions, which just happens to be one of the options that Ajax.InPlaecEditor takes... — Tyler (]

  def editable_content(options)
    options[:content] = { :element => 'span' }.merge(options[:content])
    options[:url] = {}.merge(options[:url])
    options[:in_place_editor] = { :okText => "'Save'", :cancelText => "'Cancel'"}.merge(options[:in_place_editor] || {})
    script = Array.new
    script << "new Ajax.InPlaceEditor("
    script << "  '#{options[:content][:options][:id]}',"
    script << "  '#{url_for(options[:url])}',"
    script << "  {"
    script <<      options[:in_place_editor].map{ |key, value| "#{key.to_s}: #{value}" }.join(", ")
    script << "  }"
    script << ")"

    content_tag(
      options[:content][:element],
      options[:content][:text],
      options[:content][:options]
    ) + javascript_tag( script.join("\n") )
  end
<h1>Mortal Enemies</h1>

<% unless @mortal_enemies.empty? %>
<ul>
  <% for mortal_enemy in @mortal_enemies %>
  <li>
    <%=h mortal_enemy.name %><%= editable_content(
      :content => {
        :element => 'span',
        :text => mortal_enemy.reason_to_kill,
        :options => {
          :id => "mortal_enemy_edit_#{mortal_enemy.id}",
          :class => 'editable-content'
        }
       },
      :url => {
        :controller => 'robot_hit_lists',
        :action => 'update',
        :id => mortal_enemy.id
       },
      :ajax => {
        :okText => "'is why I want to kill them'",
        :cancelText => "'Nevermind'"
       }
    ) %>
  </li>
  <% end %>
</ul>
<% end %>

...

Another example: Let's say we're editing the path to an image, and that after we save that field, we want it to update an img tag to show a preview of that image.

Here's how I did it:

      html << image_tag("icons/#{node.icon}", :alt => '', :title => 'Preview of icon', :id => "menu_item_icon_#{node.id}_img")

      html << content_tag('span',
        editable_content(
          :content => {
            :element => 'span',
            :text => node.icon,
            :options => {
              :id => "menu_item_icon_#{node.id}_in_place_editor",
              :class => 'editable-content'
            }
           },
          :url => {
            :action => 'set_menu_item_icon',
            :id => node.id
           },
          :in_place_editor => {
            :onComplete => "function(transport, element) {
              new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
              $('menu_item_icon_#{node.id}_img').src = '/images/icons/' + transport.responseText;
            }"
          }
        )
      )
Ads
Personal tools