1

I am using Amistad to implement the friendship model. I have five actions in the friendships_controller: index, request_friend, approve_friend, remove_friend, block_friend.

I am not sure on how to define the routes in the routes file, I tried using resources :friendships but am unable to make a friend request from the user profile.

Here are the files:

routes.rb:

resources :friendships

friendships_controller.rb:

class FriendshipsController < ApplicationController
    before_filter :authenticate_user!

    def index
        @friends = current_user.friends
        @pending_invited_by = current_user.pending_invited_by
        @pending_invited = current_user.pending_invited
    end

    def request_friend
        @friend = User.find(params[:id])
        #if !@friend
        #    redirect_to :back
        #end
        current_user.invite @friend
        redirect_to :back
    end

    def approve_friend
        @friend = User.find(params[:id])
        current_user.approve @friend
        redirect_to :back
    end

    def remove_friend
        @friend = User.find(params[:id])
        current_user.remove_friendship @friend
        redirect_to :back
    end

    def block_friend
        @blocking = User.find(params[:id])
        current_user.block @blocking
        redirect_to :back
    end
end

I want User A to be able to send User B a friend request and User B to either accept it, delete it or ignore it.

Here is my show.html.erb

<span> 
  <% if @user == current_user %>
    <%= link_to 'Edit Profile', edit_profile_path(@user.user_name),class: 'btn edit-button' %>
  <% elsif current_user.friend_with? @user %>Already Friends!
    <%= button_to "Delete!",friendship_path(id: @user.id, friendship_action: 'remove_friendship'), method: :delete, class: "btn btn-primary" %>
  <% elsif current_user.invited? @user %>Friend request sent!
    <%= button_to "Unsend!", friendship_path(id: @user.id), :method => :delete, class: "btn btn-small btn-primary" %>
  <% elsif current_user.invited_by? @user %>
    <%= button_to "Accept!", friendship_path(@user.id, friendship_action: 'approve'), :method => :patch, class: "btn btn-small btn-primary" %>
    <%= button_to "Reject!", friendship_path(@user.id, friendship_action: 'remove_friendship'), :method => :delete, class: "btn btn-small btn-primary" %>
  <% else %>
    <%= form_tag friendship_path(@user.id,friendship_action: 'invite') do %>
      <%= submit_tag "Request Friend", class: "btn btn-primary" %>
    <% end %>
  <% end %>
</span>

This is the process going on in console when i manually do the friendships-i.e. user1.invite user2-it is working and changes are being made in the friendhips table-i used sqlitebrowser to verify

Here is what is going on when i press the link_to in my show.html.erb.Ive only included parts of the console related to the friendship model

I dont know why the values are not being inserted when i press the button.But when i do it manually via the console they are being inserted.

Ashksta
  • 61
  • 2
  • 7
  • do i have to post the code for show.html.erb-the profile page of users – Ashksta May 26 '17 at 13:28
  • You can run `rake routes` and see what are the urls generated..that's the best way to learn by trial and error/mix matching/playing with routes and keywords.. – Md. Farhan Memon May 26 '17 at 13:51

2 Answers2

0

If I understood correctly this is how your routes.rb should look like

You can pass a block to the resources method to define nested resources.

resources :friendships do
  member do
    post 'approve_friendship', to: 'friendships#approve_friendship'
    post 'request_friendship', to: 'friendships#request_friendship'
    delete 'remove_friendship', to: 'friendships#remove_friendship'
    post 'block_friendship', to: 'friendships#block_friendship'
  end
end

This will define the endpoints as POST /friendships/:id/approve_friendship

You should check rails doc for more info: http://guides.rubyonrails.org/routing.html#adding-more-restful-actions

0

Why not just use the standard verbs?

class FriendshipsController < ApplicationController

  before_filter :authenticate_user!

  def index
    @friends = current_user.friends
    @pending_invited_by = current_user.pending_invited_by
    @pending_invited = current_user.pending_invited
  end

  def new
    @friend = User.find(params[:id])
    current_user.invite @friend
    redirect_to :back
  end

  def create
    @friend = User.find(params[:id])
    current_user.approve @friend
    redirect_to :back
  end

  def update
    @friend = User.find(params[:id])
    current_user.send blocking_method, @friend
    redirect_to :back
  end

  def destroy
    @friend = User.find(params[:id])
    current_user.remove_friendship @friend
    redirect_to :back
  end

private

  def blocking_method
    current_user.blocking?(@friend) ? :unblock : :block
  end

end

Then you can just do:

resources :friendships

Like you started with and not have to monkey around with your routes.

Also, in the update method (aka, 'blocking'), I added a toggle so that you can allow a user to block and unblock a friend.

Now, when you look at your methods, they are all essentially identical except for the call being made on current_user. So why not slim things down?

class FriendshipsController < ApplicationController
  ALLOWED_FRIENDSHIP_ACTIONS = %w('invite' 'approve' 'remove_friendship' 'block', 'unblock')

  before_filter :authenticate_user!

  def index
    @friends = current_user.friends
    @pending_invited_by = current_user.pending_invited_by
    @pending_invited = current_user.pending_invited
  end

  def update
    @friend = User.find(params[:id])
    current_user.send(friendship_action, @friend) if friendship_action
    redirect_to :back
  end

private

  def friendship_action
    if fa = params[:friendship_action]
      return fa if ALLOWED_FRIENDSHIP_ACTIONS.include?(fa)
    end
  end

end

And then you could do:

resources :friendships, :only => [:index, :update]

And use it something like:

link_to friendship_path(id: @friend.id, friendship_action: 'invite'), method: :patch

You'll have to monkey with that @friend.id bit a little depending on where you are generating your link_to (or your form, depending on how you're doing it).

I don't know. To me, that seems like cleaner code. Fewer lines, less repetition, more closely following convention. But, whatever floats your skiff.

RESPONSE TO COMMENT

Try the changes below...

This:

    <%= button_to "Delete!",friendship_path(id: @user.id, friendship_action: 'remove_friendship'), method: :delete, class: "btn btn-primary" %>

Should be this:

    <%= button_to "Delete!", friendship_path(id: @user.id, friendship_action: 'remove_friendship'), method: :patch, class: "btn btn-primary" %>

Why? Because you don't have a delete method anymore, remember? Only index and patch.

Change this:

    <%= button_to "Unsend!", friendship_path(id: @user.id), :method => :delete, class: "btn btn-small btn-primary" %>

To this:

    <%= button_to "Unsend!", friendship_path(id: @user.id, friendship_action: 'unsend'), method: :patch, class: "btn btn-small btn-primary" %>

You need the friendship_action inside the helper. And, again, :delete becomes :patch.

This:

    <%= button_to "Accept!", friendship_path(@user.id, friendship_action: 'approve'), :method => :patch, class: "btn btn-small btn-primary" %>

I would change to:

    <%= button_to "Accept!", friendship_path(id: @user.id, friendship_action: 'approve'), method: :patch, class: "btn btn-small btn-primary" %>

Adding id: in front of @user.id may be the thing. Here, you got the :method, but I would reformat to method: :patch just to be consistent.

Here:

    <%= button_to "Reject!", friendship_path(@user.id, friendship_action: 'remove_friendship'), :method => :delete, class: "btn btn-small btn-primary" %>

Change to:

    <%= button_to "Reject!", friendship_path(id: @user.id, friendship_action: 'remove_friendship'), method: :patch, class: "btn btn-small btn-primary" %>

Adding id and :delete to :patch.

Finally, this:

    <%= form_tag friendship_path(@user.id,friendship_action: 'invite') do %>
      <%= submit_tag "Request Friend", class: "btn btn-primary" %>
    <% end %>

To this:

    <%= button_to "Request Friend", friendship_path(id: @user.id, friendship_action: 'invite'), method: :patch, class: "btn btn-primary" %>

You're using button_to everywhere else. Why not here, too?

Here it is, all together:

<span> 
  <% if @user == current_user %>
    <%= link_to 'Edit Profile', edit_profile_path(@user.user_name),class: 'btn edit-button' %>
  <% elsif current_user.friend_with? @user %>Already Friends!
    <%= button_to "Delete!", friendship_path(id: @user.id, friendship_action: 'remove_friendship'), method: :patch, class: "btn btn-primary" %>
  <% elsif current_user.invited? @user %>Friend request sent!
    <%= button_to "Unsend!", friendship_path(id: @user.id, friendship_action: 'unsend'), method: :patch, class: "btn btn-small btn-primary" %>
  <% elsif current_user.invited_by? @user %>
    <%= button_to "Accept!", friendship_path(id: @user.id, friendship_action: 'approve'), method: :patch, class: "btn btn-small btn-primary" %>
    <%= button_to "Reject!", friendship_path(id: @user.id, friendship_action: 'remove_friendship'), method: :patch, class: "btn btn-small btn-primary" %>
  <% else %>
    <%= button_to "Request Friend", friendship_path(id: @user.id, friendship_action: 'invite'), method: :patch, class: "btn btn-primary" %>
</span>
jvillian
  • 19,953
  • 5
  • 31
  • 44
  • i am getting this error when i click the reject button: No route matches [DELETE] "/friendships/2" also none of them are working-accept,reject,request friend,unsend,delete friend. @jvillian i used the shortened controller and the route you mentioned. – Ashksta May 27 '17 at 03:40
  • i have added the show.html.erb file above.i'm sorry it is lacking indentation.i could not figure out how to add indentation. – Ashksta May 27 '17 at 03:52
  • hey @jvillian i have done everything it still is not working,when i press the button nothing happens.i have checked the console some changes are going on but the friendships table is not being modified to reflect the changes. i am able to manually create the relations from console using u1.invite u2,u2.approve u1 and so on – Ashksta May 27 '17 at 19:17
  • these are what the links look like: localhost:3000/friendships/4?friendship_action=invite localhost:3000/friendships/1?friendship_action=unsend localhost:3000/friendships/2?friendship_action=approve localhost:3000/friendships/2?friendship_action=remove_friendship i am unable to figure why it is not working via the links-no errors,just nothing happens when i click the button-everything gets reloaded when i press the button-as observed from the rails console – Ashksta May 27 '17 at 19:51
  • It sounds promising and the links look good. Can you add to your question what is happening in console. – jvillian May 27 '17 at 20:07
  • i posted the links to the screenshots ,above. – Ashksta May 28 '17 at 04:06
  • At this point, I've answered your original question plus given you a cleaner controller strategy and helped you properly configure button_to. If you want additional help, I suggest you accept this answer and ask a new question. – jvillian May 28 '17 at 16:43
  • i've got it working but the code is repetitive.Would really like to get your implementation working.Can you identify why the implementation you've given doesnt function as intented based on the solution i've provided. – Ashksta May 30 '17 at 15:30