smholloway
smholloway

Reputation: 587

Rails3: Is there a best practice for updating attributes without a form?

I've been stuck on this for a few days and I'm afraid I lack the vocabulary to properly ask this question, but any feedback is greatly appreciated!

I am working on a basic blog site. Users can create posts with a title, description, and declare whether others can see the post (public or private). From the index page, I want the user to be able to see a list of their posts, toggle public|private, and delete the post. Listing is easy (I'm rendering a partial based on the user's posts), and the AJAX delete link is working nicely:

<%= link_to 'Delete Post', post, :confirm => 'Are you sure?', :method => :delete, :remote => true %>

Toggling public|private corresponds to an edit/update action, and I cannot figure out how to do that using a link or button--it seems I have to use a form. I've tried a lot of variations of the working delete button that look something like this (and none work):

<%= link_to 'Make Public', { :controller => "posts", :action => "update", :id => post, :public => true, :post => post }, :method => :put, :remote => true %>

The only way that seems to work is with a form, but this requires that the user click the Update Post button:

<%= form_for(post, :remote => true) do |f| %>
  <div class="field">
    <%= f.label :public %><br />
    <%= f.check_box :public %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

So, in Rail3 what is the proper way to update a single attribute? (Is there more fitting verbiage?) Can it be done using a link or button? Do I have to use a form? Is there a Rails3 way (like destroy.js.erb) to add an onclick/onchange event or do I need to develop my own JavaScript?


Zabba's answer is great; however, I ultimately used a hidden form submitted via JavaScript (specifically jQuery).

In the view:

<div>
  <%= form_for(post, :remote => true) do |f| %>
    <%= f.hidden_field :public, { :value => !post.public } %>
  <% end %>
  <% if post.public == true %>
    <div class="pp">Public</div>
  <% else %>
    <div class="pp">Private</div>
  <% end %>
</div>

The JavaScript:

$('.pp').live('click', function(){
  $(this).siblings('form').submit();
});

Comments on the two approaches? Is one more idiomatic?

Upvotes: 2

Views: 1094

Answers (1)

Zabba
Zabba

Reputation: 65497

I would do it this way (not tested, so might be some minor mistakes):

  1. Create action named make_public in PostsController

    a. The link" would be: <%= button_to 'Make Public', :confirm => 'Are you sure?', :method => :put, :remote => true %>

    b. The action will receive the posts's id (params[:id])

  2. Define a method called make_public on the Post model a. Call update_attributes :make_public => true

The link that does the update should be a PUT not a GET (Always put all state-changing actions behind a POST or a PUT)

Upvotes: 4

Related Questions