0

I have two models : User and Product. One user has many owned_products, and a product belongs to an owner. The products have a available:boolean.

I want to make a list of owned_products that can be toggled from available to unavailable with a button. Here is what I did, using the M. Hartl example :

app/views/shared/_owned_products_list.html.erb

<ol class="products">
  <% @owned_products.each do |product| %>
    <%= link_to(product.name, product) %>
    <%= render 'products/available_form', product: product %>
  <% end %>
</ol>

app/views/products/_available_form.html.erb

<div id="available_button_<%=product.id%>">
 <% if product.available? %>
    <%= form_for(product, remote: true) do |f| %>
      <div><%= f.hidden_field :available, value: nil %></div>
      <%= f.submit t('product.available.undo'), class: "btn btn-small" %>
    <% end %>
  <% else %>
    <%= form_for(product, remote: true) do |f| %>
      <div><%= f.hidden_field :available, value: true %></div>
      <%= f.submit t('product.available.do'), class: "btn btn-primary btn-small" %>
    <% end %>
  <% end %>
</div>

app/controllers/products_controller.rb

    .
    .
    .
  def update
    @product = Product.find(params[:id])
    if @product.update_attributes(product_params)
      respond_to do |format|
        format.html do
          flash[:success] = t('flash.success.product.update')
          redirect_to @product
        end
        format.js
      end
    else
      render 'edit'
    end
  end
    .
    .
    .

app/views/products/update.js.erb

$("#available_form_<%[email protected]%>").html("<%= escape_javascript(render('available_button', product: @product)) %>")

But it doesn't work : The available button is not refreshed at all :

When I click on the available (or unavailable) button, nothing change. If I refresh the whole page, it toggles, regardless the number of clicks...

Do you know where I failed ?

EDIT

OK, I got it, it was a dumb fault : my available_form id was available_button_<%[email protected]%> and not available_form_<%[email protected]%>...

So here is the right one :

app/views/products/update.js.erb

$("#available_button_<%[email protected]%>").html("<%= escape_javascript(render('available_button', product: @product)) %>")

1 Answer 1

1

I assume that you're using rails with jquery and jquery_ujs, make it simple:

in app/views/shared/_owned_products_list.html.erb

<ol class="products">
  <% @owned_products.each do |product| %>
    <%= link_to product.name, product %>
    <%= link_to product.available ? 'turn off' : 'turn on', '#', :class => 'toggle-availability', :'data-id' => product.id %>
  <% end %>
</ol>

in your js-script file:

$.ajaxSetup({
  headers: {
    'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
  }
});    

$(document).on('click', '.toggle-availability', function() {
   var el = $(this);
   var status = el.text();
   $.post('/products/toggle', { id: el.data('id') }, function() {
      el.text(status == 'turn off' ? 'turn on' : 'turn off');
   });
   return false;
});

in the controller file:

def toggle
  if request.xhr?
     product = Product.find(params[:id])
     # note here that you should also check the owner of the product
     product.available = product.available.nil? ? true : false
     product.save
  end
  render :nothing => true
end

and in your routes.rb add:

resources :products do
  collection do
    get :toggle
  end
end
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you ! It will be helpful. But do you know why it doesn't work my way ?
Ok, first of all I don't see in your code any tag with #available_form_<%[email protected]%>, only available_button_<%=product.id%>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.