Question

So I'm creating a photo proofing web app for a client. I want him to be able to skim the images on the site and under each image is an 'Approve' button, which he can click and the image border will turn green, signaling it's good for export.

Now my JS/Jquery knowledge is pretty limited, but I know that this might go deeper than just front-end work, because I want to see those changes even after browser is closed, which I think requires a both back-end and front-end solution.

I'm thinking to create a boolean attribute under my image model, and when you click the 'Approve' button, it'll switch the boolean value to true, which will change the css class to turn green. Is there a way rails can detect a boolean value and change the css accordingly? I want to be able to see the changes my client made.

Would appreciate any feedback/advice on my approach, or if there's a better way out there to go about this. Thanks!

Was it helpful?

Solution 3

Thanks everyone who helped me answer this question below! I came up with a solution I'm pretty happy about, figured I'd share it hoping it'll help somebody else along the way.

The problem: I was looking for an AJAX solution that could make permanent changes to the data model. I wanted somebody to be able to toggle/highlight certain items on a page, and have those changes saved on the backend so I can view it later.

This required both a front-end ajax solution for the user interface and back-end solution so the ultimate changes will be saved in the data model so when I load up the site later, I can see the changes he made.

My solution (with the help of those who answered below):

  • Backend - I created a link that when pressed, would toggle the attribute in my model either true/false
  • Frontend - In order to give the client a real-time feel, I had to set the link to perform ajax requests and change the css accordingly.

My controller:

  def approve
    @pipe = Pipe.find(params[:id])
    respond_to do |format|
        if @pipe.toggle!(:approved)
            format.html { redirect_to root_url }
            format.js
        else
            format.html { render :index }
        end
    end
  end

My pipes table has an approved:boolean attribute

My approve.js.erb file (I wrapped each pipe in a div using div_for(@pipe):

<% if @pipe.approved? %>
        $('div#<%= dom_id(@pipe) %>').children('.flexslider').css('border','4px solid green');
        $('div#<%= dom_id(@pipe) %>').children('a').text('un-approve');
<% else %>
        $('div#<%= dom_id(@pipe) %>').children('.flexslider').css('border','4px solid white');
        $('div#<%= dom_id(@pipe) %>').children('a').text('approve');
<% end %>

My Application Helper:

def approve_text(approvable)
    approvable.approved? ? 'un-approve' : 'approve'
end

My trigger link (which uses abovementioned helper):

<%= link_to approve_text(pipe), approve_pipe_path(pipe), remote: true, method: 'PUT', class: approve_text(pipe) %>

My routes:

  resources :pipes do
    member do
        put :approve
    end
  end

Again, thanks for those who helped provide answers. This is a solution I'm pretty happy with. I know it probably could use some help being refactored. If anyone has suggestions, would love to hear about it!

OTHER TIPS

first add on your images table an approved column with type boolean and on your images controller and these action

def approve
@image =Image.find(params[:id])
@image.update_column(:approved,true)
respond_to do |format|
format.js
end
end

in routes add these method

resources :images do
member do 
put :approve
end   
end 

in your html

 <div class="image">
<img src="<%=@image.source%>" />
 <%= link_to "approve",approve_image_path(@image),:remote=>true,:method=>"PUT",:class=>"approve_me"%>

</div>

in your image.js file add these method

 $("body").on("click",".approve_me",function(e){
 e.preventDefault();
 $(this).parents(".image").find("img).css("border-color","green");
 });

I think you are almost there.

Firstly - yes, changing the css with javascript on runtime will immediately change the appearance of dom elements.

On the client side - you want to indicate to the user which images have been selected, but you also need to store the approved value for each element in your submit form.

In Rails it is common to create hidden input elements storing additional data. Given the task at hand - they can store a value of 0/1 - rejected/approved. You can come up with your own convention for naming the image/select values.

Then, in your view, add onclick listeners to your images pointing to a javascript function:

1) checking if the clicked element is already selected, 2) changing the css of the current element, 3) updating the hidden input value for that element.

Here is a dummy demonstration - jsfiddle

Later, you can then get the approved/rejected value from the params in your controller, like (see below).

In case you want to assign a css class when constructing the view and depending on an approved flag value, you could do something like:

 <img id="image_<%= image_id %>" src="<%= image_item.path"  class="<%= (image_item.approved.to_i == 1) ? 'approved_img' : 'non_appr_img' %>" %>
 <input id="image_<%= image_id %>_app_flg" type="hidden" value="<%= image_item.approved %>" />

where image_item is an object properties path and approved (self explanatory), image_id the id of the image object, approved_img and non_appr_img - css classes.

I'm not discussing the back-end for storing the approved flag, as it seems it is out of the scope of the question

EDIT

Brief concerning back-end

Given the you have an images model, extend it to include an approval property (prepare a database migration and edit your model .rb file to include the new columns).

In the view, include all of the hidden inputs inside a form which will be submitted to your controller(for example looping through an array on your images). For example:

 <%= form_for :images, :url => {:action => "approve_images"}, :html => {:name => "testForm"}  do |f| %>
   <!-- TODO do stuff here - eg display images -->
   <% @images.each do |imageItem| %>
     <%= f.hidden_field "#{imageItem.id}_appproved", {:value => imageItem.approved}%>
   <% end %>
   <!-- TODO add a submit button -->
 <% end %>

*You need to Here :images is the controller, approve_images is the function in the controller that the form will be submitted to (include in routes), @images is an array with images data (from your model) and that you have prepared in the controller before rendering the view. I assume the images have ids and approved property.

This will yield in your view dom elements like this:

<input id="images_IMAGEID_appproved" name="images[IMAGEID_approved]" type="hidden" value="1" />

After submitting the form, in your controller you will be able to access these values like this:

img_approved = params[:images][IMAGEID+"_approved"]

Finally you can store that value to your database. Good luck! :)


I am omitting a lot of even more basic things, but I think the question is too broad as it is and there are plenty of resource detailing how to create,read,write a model, prepare data for the view etc. If not - please get started with http://guides.rubyonrails.org/getting_started.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top