Rails passing params in link_to how to make it secure

I am trying to create a like and dislike function inside rails for that I am using lin_to helper to pass params but there is an issue when ever someone tries to copy paste the links it updated the database . I am using ajax to make this function work here is the code for my method .

Controller code :

 class FeedLikesController < ApplicationController
            before_action :authenticate_user! ,only: [:create, :destroy]
             before_action :get_feed ,only: [:create, :destroy]

              def index
@fees = FeedLike.                all
respond_to do |format|

                        format.                        html format.

             js
end
              end
             def update
@feed_likes = FeedLike.find_or_create_by(feed_like_params)
                    respond_to do |format|
                        if @feed_likes.                        save
format.html { redirect_to root_url, notice: 'Like ' }

                        else

                        end
                   end
            end
              def create
@feed_like_counter= Feed.find(params[:feed_id])
                    @feed_likes = FeedLike.find_or_create_by(:feed_id => params[:feed_id],:user_id =>params[:user_id])
                     @f = @feed_like_counter.                     like_count
@feed_like_counter.like_count = @f+1
                     @feed_like_counter.                    save
respond_to do |format|
                        if @feed_likes.                        save format.html { redirect_to root_url, notice: 'Like ' }
                        format.                        js
else

                        end
                   end
              end

              def delete

              end

              def destroy
@feed_like_counter= Feed.find(params[:feed_id])
                  @feed_likes = FeedLike.where(feed_like_params)
                  @f = @feed_like_counter.                  like_count
@feed_like_counter.like_count = @f-1
                  @feed_like_counter.                  save
respond_to do |format|
                       if @feed_likes.                       destroy_all
format.html { redirect_to root_url, notice: 'Unlike ' }
                       format.                       js
else

                       end
                   end
              end
              def feed_like_params
params.permit(:user_id, :feed_id)
                  #params[:market_place]
                end
            def get_feed
@feed= Feed.find(params[:feed_id])
            end

              end

And in views my link is like this :

  <div class="feed-like-<%= @feed %> " >
<%= link_to "like",{ :action => 'create', :controller => 'feed_likes', :feed_id => @feed, :user_id => current_user.id, :remote => true }, method: :post,class: "btn btn-primary"   %>
</div>

And dislike link is like this :

        <div class="feed-like-<%= @feed %> " >
<%= link_to "Dislike",{ :action => 'destroy', :controller => 'feed_likes', :feed_id => @feed, :user_id => current_user.id, :remote => true }, class: "btn btn-primary" %>
</div>

And my routes is like :

   get "/feed_likes/:feed_id/feed_likes/:user_id" => "feed_likes#destroy"
      post "/feed_likes/:feed_id/feed_likes/:user_id" => "feed_likes#create"

Here the issue is whenever someone wants to like the feed when I passes the url direclty it updated the database how can I restrict this only when user click the button only then it update the database not by url :

There is another issue with this I am using ajax onclick event it updated the database but when I click the like button fast it update the databse 2 or 3 times before the dislike partial appear . Is there any way I can use this .

http://ec2-52-6-228-48.compute-1.amazonaws.com/ Here is the live application I am working on here there is a like button when I click on like button it update my database that it liked and dislike button appear it work well but when I click very fast 3 times before dislike appear it sneds three ajax request . And it is a very bad thing how to fix this

Hi Nilay,

The first thing I would do, would be to strip out your controller code and move your logic into the model. You’ve got too much going on in your create and destroy actions. This should be in the model.

The controller should be responsible for receiving the request, and sending the response back to the browser in the correct format, while the model should be responsible for handling the business logic.

I am trying to create a like and dislike function inside rails for that I am using lin_to helper to pass params but there is an issue when ever someone tries to copy paste the links it updated the database . I am using ajax to make this function work here is the code for my method .

Controller code :

 class FeedLikesController < ApplicationController
            before_action :authenticate_user! ,only: [:create, :destroy]
             before_action :get_feed ,only: [:create, :destroy]


              def index
@fees = FeedLike.                all
respond_to do |format|

                        format.                        html format.

             js
end
              end
             def update
@feed_likes = FeedLike.find_or_create_by(feed_like_params)
                    respond_to do |format|
                        if @feed_likes.                        save
format.html { redirect_to root_url, notice: 'Like ' }

                        else

                        end
                   end
            end
              def create
@feed_like_counter= Feed.find(params[:feed_id])
                    @feed_likes = FeedLike.find_or_create_by(:feed_id => params[:feed_id],:user_id =>params[:user_id])
                     @f = @feed_like_counter.                     like_count
@feed_like_counter.like_count = @f+1
                     @feed_like_counter.                    save
respond_to do |format|
                        if @feed_likes.                        save format.html { redirect_to root_url, notice: 'Like ' }
                        format.                        js
else

                        end
                   end
              end


              def delete

              end

              def destroy
@feed_like_counter= Feed.find(params[:feed_id])
                  @feed_likes = FeedLike.where(feed_like_params)
                  @f = @feed_like_counter.                  like_count
@feed_like_counter.like_count = @f-1
                  @feed_like_counter.                  save
respond_to do |format|
                       if @feed_likes.                       destroy_all
format.html { redirect_to root_url, notice: 'Unlike ' }
                       format.                       js
else

                       end
                   end
              end
              def feed_like_params
params.permit(:user_id, :feed_id)
                  #params[:market_place]
                end
            def get_feed
@feed= Feed.find(params[:feed_id])
            end

              end

And in views my link is like this :

  <div class="feed-like-<%= @feed %> " >
<%= link_to "like",{ :action => 'create', :controller => 'feed_likes', :feed_id => @feed, :user_id => current_user.id, :remote => true }, method: :post,class: "btn btn-primary"   %>
</div>

And dislike link is like this :

        <div class="feed-like-<%= @feed %> " >
<%= link_to "Dislike",{ :action => 'destroy', :controller => 'feed_likes', :feed_id => @feed, :user_id => current_user.id, :remote => true }, class: "btn btn-primary" %>
</div>

And my routes is like :

   get "/feed_likes/:feed_id/feed_likes/:user_id" => "feed_likes#destroy"
      post "/feed_likes/:feed_id/feed_likes/:user_id" => "feed_likes#create"

Here the issue is whenever someone wants to like the feed when I passes the url direclty it updated the database how can I restrict this only when user click the button only then it update the database not by url :

There is another issue with this I am using ajax onclick event it updated the database but when I click the like button fast it update the databse 2 or 3 times before the dislike partial appear . Is there any way I can use this .

Think about what is happening when you click the link.

A request is sent to the server, which is picked up by your app and routed to your controller, which then handles the request, and sends a response back to the browser - this is going to take longer then it takes for you to click your link multiple times - therefore your app handles each click exactly as you have designed it to.

If this situation becomes too problematic, then it is probably a code smell that your design is wrong and needs to be looked at again.

I don’t get why your dislike button only appears after a click on the like button. Do you really need to like something before you can dislike it?

A simple fix would be to add some Javascript that removes the link from the page after the first click before the request is sent to the browser, and maybe display an indictor/spinner that informs the user that the click is currently being handled.

Regards

Paul

Thanks for reply paul . If you can suggest me how should I use these controllers code in model I am new to rails so I am not aware about this method . And for this problem I found a way to delay the process using disable_with method in rails and it fix the problem by delaying the process .

So here is the solution code :

<%= link_to “Dislike”,{ :action => ‘destroy’, :controller => ‘feed_likes’, :feed_id => @feed, :user_id => current_user.id, :remote => true },data: { disable_with: “Processsing…” }, class: “btn btn-primary” %>

And paul there is one more problem . I need to fix that you can see the url of my links are passsing the params is it a right way if yes then ok but the problem is When I paste the url direclty in the browser it get updated how can I prevent this .

Hi Nilay,

Ruby and Rails are changing all the time, so it’s always useful to post which versions you are using, if I missed it in your post I apologise.

Thanks for reply paul . If you can suggest me how should I use these controllers code in model I am new to rails so I am not aware about this method .

In which case I would suggest following a few Rails tutorials. A quick google for ‘Rails Tutorials’ is a good starting point. You will end up getting more done, faster, if you take the time out to follow one or two of those.

You should also have a decent understanding of Ruby and MVC frameworks.

That said, I’ll assume the following and try to help.

You have a model: Feed

And a model: FeedLike

Feed has_many :feed_likes

FeedLike belongs_to :feed

Your create action could be as simple as follows:

def create

@feed_like = FeedLike.find_or_create_by(:feed_id => params[:feed_id],:user_id =>params[:user_id])

@feed_like.increment

respond_to do |format|

if @feed_like.save

end

end

end

Then, in your FeedLike model you could add the following method:

def increment

self.feed.like_count ++

end

(If you have your models set up correctly then the increment method should be fine because rails will create the feed method on the FeedLike model, which points to the Feed model. This then gives you access to the like_count method of the Feed model.)

Your destroy method could be as follows:

def destroy

@feed_like = FeedLike.where(feed_like_params)

@feed_like.decrement

respond_to do |format|

if @feed_like.destroy

end

end

end

(I’m not sure why you’re calling destroy_all)

Then in your FeedLike model:

def decrement

self.feed.like_count –

self.feed.save

end

You need to call save here, because calling destroy on the FeedLike model won’t automatically save the Feed model relation.

Personally I would set this all up to go through the Feed controller, which would also make your links and routes easier to set up.

And for this problem I found a way to delay the process using disable_with method in rails and it fix the problem by delaying the process .

So here is the solution code :

<%= link_to “Dislike”,{ :action => ‘destroy’, :controller => ‘feed_likes’, :feed_id => @feed, :user_id => current_user.id, :remote => true },data: { disable_with: “Processsing…” }, class: “btn btn-primary” %>

And paul there is one more problem . I need to fix that you can see the url of my links are passsing the params is it a right way

Probably not the way you have set your routes up. Where did you get the information from to create them as you have?

You don’t seem to be doing anything out of the ordinary to need such custom routes for your create and destroy methods, so, if you use the following method for your controller routes you will get the standard routes that you should be working with.

In routes.rb

resources :feed_likes

What you will need to do, is to pass the feed_id and the user_id as parameters on your links rather than coding them into the route as you have. You can also tidy up your links using the routes helper methods such new_feed_like.

Run ‘rake routes’ from the command line to see what your routes look like and what helpers are available.

if yes then ok but the problem is When I paste the url direclty in the browser it get updated how can I prevent this .

Fix your routes, then see if this is still a problem.

Obviously all the above is untested, and it’s getting late here, so hopefully I’ve helped you on the right path.

Regards

Paul

You shouldn’t be doing something that changes the database from a GET route. I’d change that route to use the delete method instead of get (and then change the link too)

Fred

I solve the issue

Sure for my first question I made some changes to my routes file here I use resources for my model which generated the routes and then I write this code in link : This is what I change in route :

resources :feed_likes, param: :feed_id

and this is my links which I am passing the params :

it is for dislike :

<%= link_to "Dislike", feed_like_path(:feed_id => @feed, :user_id => current_user.id ), :confirm => 'Are you sure?',:remote => true, :method => :delete,data: { disable_with: "Processsing..." }, class: "btn btn-primary" %>

and this is for like :

<%= link_to "like", feed_likes_path(:feed_id => @feed, :user_id => current_user.id ), :confirm => 'Are you sure?',:remote => true, :method => :post, data: { disable_with: "Processsing..." }, class: "btn btn-primary" %>

And for delaying the process I use disable_with

It served my purpose

Do you think it might be good manners to thank those that provided helpful ideas?

Colin

Nilay,

Why did u use Feed and FeedLike model? The solution provided by Liz is good. You can pass binary values for updating the like and dislike value, instead of having two different models.

And definitely your code needs lot of cleanups. Google for code cleanups, refactoring in rails.

-Saurav