I'm currently having issues with destroying a friendship in ruby on rails. The friendships are being created normally (I tested this using rails console), but deleting the friendship is not working.
Below is my controller code:
class FriendshipsController < ApplicationController
def create
#current_friend = User.find(params[:friend_id])
#friendship = current_user.friendships.build(:friend_id => #current_friend.id)
#friendship_2 = #current_friend.friendships.build(:friend_id => current_user.id)
if #friendship.save && #friendship_2.save
flash[:notice] = "Friend added"
redirect_to current_user
else
flash[:notice] = "Can not add friend"
redirect_to current_user
end
end
def destroy
#friendship = current_user.friendships.find_by(friend_id: params[:id]).first
if #friendship.exists?
#friendship.destroy
end
#friendship_2 = Friendship.where(user_id: params[:id], friend_id: current_user.id).first
if #friendship_2.exists?
#friendship_2.destroy
end
flash[:notice] = "Friendship destroyed"
redirect_to current_user
end
end
Below is my form for deleting the friendship:
<%= form_for(current_user.friendships.find_by(friend_id: #user.id),
html: { method: :delete }) do |f| %>
<%= f.submit "Unfriend", class: "btn" %>
<% end %>
Note that I added the check for the friendship existing since I just kept getting an error stating that the friendship was nil, which is my current problem.
Thanks!!!
In your view you're looking up the friendship with the friend_id (which you're supplying #user.id to), and that Friendship is what you're sending to form_for, so your form will have the :id of the Friendship.
But then in your destroy action you use params[:id] (the friendship id) in your query as the friend_id (which you've previously demonstrated should be a User id not a Friendship id.
Your code should actually be:
#friendship = current_user.friendships.find_by(id: params[:id])
(and you shouldn't be calling .first on that at all because find_by already returns a single record)
Related
I'm new to rails and have stuck with a simple thing.
I have a method to add new members to the team:
def add_member
#team = Team.find(params[:id])
#team.members << User.find(params[:user_id])
redirect_to #team
end
Every team has its author. I want the author to add a registered user to his team like this:
My add button:
= link_to 'Add member', add_member_team_path(#team, user_id: user.id)
So if user with the email exists, he should be added to #team.members.
How to pass user.id from email_field_tag to my link button?
Sorry, if the question is silly. Many thanks in advance!
UPDATE
Now the code look this way:
Controller:
def add_member_by_email
#team = Team.find(params[:id])
#user = User.find_by_email(params[:email])
if #user.nil?
render text: "No user found with that email" and return
else
#team.members << #user
redirect_to #team
end
end
In my view:
= email_field_tag :user_email
= link_to 'Add to team', add_member_by_email_team_path(#team, email: :user_email)
In routes.rb:
resources :teams do
member do
get :add_member_by_email
end
end
But keeps saying, there is no such user.
In your view, use a form helper, which will render an html form tag:
= form_for User.new, url: add_member_path(#team) do |f|
= f.text_field :email
= f.submit "Add new member"
In the controller, you can access the user email like this:
params[:user][:email]
Note: please excuse any typos or syntax errors in my post for now as I am writing this from the mobile app.
You should pass the email address from your email_field_tag, and in your add_member action:
def add_member
#team = Team.find(params[:id])
user = User.find_by_email(params[:email])
if !user.nil?
#team.members << user
#team.save
redirect_to #team
else
# Cannot find the user with the email address, do something here based on your design
end
end
You probably want to create a new path for this (and not just scab it on to the existing add_member path), something like:
def add_member_by_email
#team = Team.find(params[:id])
#user = User.find_by_email(params[:user_email])
if #user.nil?
render :text => "No user found with that email" and return
end
#team.members << #user
redirect_to #team
end
And update your form:
= link_to 'Add member', add_member_by_email_team_path(#team)
Making sure that the email text field gives a user_email parameter.
Trying to update 2 attributes to a User model, this is my current code in the Users controller:
def update
#user = User.find(params[:id])
if #user.update_attributes(songkickID: params[:user][:songkickID], jamID: params[:user][:jamID])
redirect_to #user
else
redirect_to #user
end
end
The Songkick ID and the Jam ID are entered into 2 different fields. However, with the current code, if I attempt to update the Jam ID on its own, it updates that attribute, but then redirects to the user page (as expected), where the Songkick ID is now nil. Upon entering the Songkick ID again, the Jam ID becomes nil. I suppose this is because they are both part of the same if statement in the controller?
I attempted to use an elsif for the jamID params, but it does not seem to recognise at all (i.e. won't update that attribute for the user). Also attempted || conditional operator.
EDIT: Here's the 2 different forms:
<%= form_for(#user) do |f| %>
<%= f.text_field :jamID, :id=>"jamURL" %>
<%= f.submit "Jam ID", :onclick => "changeImg()", id: "saveJam" %>
<% end %>
and
<%= form_for(#user) do |f| %>
<%= f.text_field :songkickID %>
<%= f.submit "Songkick ID", :type => :image, :src => image_path("songkicklogo.png"), id: "skLogo" %>
<% end %>
And I tried modifiying the code to update_column, but I get wrong number of arguments (1 for 2).
EDIT 2: Following layout from Hartl's Rails Tutorial, I attempted this to define strong parameters:
private
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
But I still get the Forbidden Attributes Error?
EDIT 3: The following code passes, but I worry it doesn't adhere to Rails 4 strong parameters:
Controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
redirect_to #user
end
end
end
If I move update to below the update method, I get an undefined variable/method error for user_params, and I cannot make it private.
So - why are you explicitly naming the attributes in your update_attributes?
You should be able to use the following:
#user.update_attributes(params[:user])
Remember that if you've named your form fields correctly, params[:user] is a hash that will already have the keys you want (:songkickID etc)
Now - you will get one of two things coming through to your action, which you then pass through to update_attributes as:
{:songkickID => someID}
{:jamID => someOtherID}
which will correctly update your user and only change the one that is passed.
The problem with your earlier code was that what you passed to update attribute was:
{:songkickID => someID, :jamID => nil}
{:songkickID => nil, :jamID => someOtherID}
which was deliberately overwriting the other id with the nil you passed.
EDIT from OP: Thanks for this, and here's my final controller code:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
redirect_to #user
end
end
private
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
end
In last case scenario:
def update
if params[:user][:songkickID]
received_param = { songkickID: params[:user][:songkickID] }
elsif params[:user][:jamID]
received_param = { jamID: params[:user][:jamID] }
end
#user.update_attributes(received_param)
redirect_to #user
end
Note: I removed the last condition since it wasn't useful
Rails 3.2, Twitter App
UPDATE: Sovled but any idea why it might work once, then when i try it again, I get Unknown key: #<User:0x007f9a5a946708> On line 16 users_controller.rb for #user. If i update a status or re-login its fine.
SOLUTION: After adding a notice: "Added", redirect_to_path under each if/else it worked fine. I haven't been able to produce an error for "user not found" tho.
I got a form_for, I type in :username, it follows or unfollows. Unfollow don't work. Looks like this.
Error
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "id"
LINE 1: DELETE FROM "relationships" WHERE "id"."follower_id" = 1 AND...
^
: DELETE FROM "relationships" WHERE "id"."follower_id" = 1 AND "id"."followed_id" = 2
id is missing? So I think the problem is in relationship_controller.rb
/users/buddies.html.erb
<%= form_for :username, :url => {:action => :buddies} do |f| %>
<%= f.text_field #user, placeholder: "username" %>
<%= f.submit "Add/Subtract" %>
<% end %>
users_controller.rb
#user = User.find_by_username(params[:username])
if #user
unless #user.blank?
if current_user.following? #user
current_user.unfollow #user
else
current_user.follow #user
end
else
flash[:error] = "stupid error";
end
end
user.rb
def following? user
self.followeds.include? user
end
def follow user
Relationship.create follower_id: self.id, followed_id: user.id
end
def unfollow user
Relationship.delete follower_id: self.id, followed_id: user.id
end
relationships_controller.rb
def create
#relationship = Relationship.new(params[:relationship])
##relationship.followed_id = params[:followed_id]
#relationship.follower_id = current_user.id
if #relationship.save
redirect_to buddies_path, notice: "Phriend added"
else
flash[:error] = "Phriend not added";
redirect_to buddies_path
end
end
def delete
#relationship = Relationship.find(params[:id])
#relationship.delete
redirect_to buddies_path, notice: "Phriend subtracted"
end
So that's a lot of words, but look in Relationship.delete.. what needs to change there?
Relationship.delete is expecting an id. Try something like:
# app/models/user.rb
def unfollow user
Relationship.where(:follower_id => self.id, :followed_id => user.id).first.delete
end
Or, perhaps a bit clearer, if followeds are relationships:
def unfollow user
self.followeds.where(:followed_id => user.id).first.delete
end
#didn't work for #ladiesman217
I can't seem to get Amistad friendships to work correctly. I am getting the following error:
ActiveRecord::RecordNotFound in FriendshipsController#update
Couldn't find Friendship with id=29
I am also using devise and cancan. I followed the gem setup on the wiki pages and created my controller as described in this related post.
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 create
#friend = User.find(params[:user_id])
#friendship_created = current_user.invite(#friend)
if #friendship_created
redirect_to users_path, :notice => "Your friend request is pending"
end
end
def update
#friend = User.find(params[:user_id])
#friends = current_user.friends
#pending_invited_by = current_user.pending_invited_by
redirect_to users_path, :notice => "You are now friends!"
end
def destroy
#friend = User.find(params[:user_id])
#friendship = current_user.send(:find_any_friendship_with, #friend)
if #friendship
#friendship.delete
#removed = true
redirect_to users_path, :notice => "You are no longer friends!"
end
end
def createblock
#friend = User.find(params[:user_id])
current_user.block #friend
redirect_to users_path, :notice => "You have blocked #{#friend.first_name}"
end
end
I loop though my users in the following manner checking the current status of the user and offering appropriate actions.
<% if current_user.friend_with? user %>
<%= link_to "Unfriend", friend_path(user), :method => "delete", :class => 'btn btn-mini' %>
<% elsif current_user.invited? user %>
<span class="btn btn-mini disabled">Pending</span>
<% elsif user.invited? current_user %>
<%= link_to "Accept", friend_path(user), :method => "put", :class => 'request-approve btn btn-mini' %>
<%= link_to "Decline", friend_path(user), :method => "delete", :class => 'request-decline btn btn-mini' %>
<% else %>
<%= link_to "Add friend", friends_path(:user_id => user), :method => "post", :class => 'btn btn-mini' %>
<% end %>
Figured it would be useful to see what the friendships table looks like in my schema:
create_table "friendships", :force => true do |t|
t.integer "friendable_id"
t.integer "friend_id"
t.integer "blocker_id"
t.boolean "pending", :default => true
end
add_index "friendships", ["friendable_id", "friend_id"], :name => "index_friendships_on_friendable_id_and_friend_id", :unique => true
I understand the error just cannot figure out how this should change. I think my issue is that I am passing in a friend id and it is expecting a friendship id. My only problem with this solution is that every example or post I can find suggests passing user_id, like this post above where the answerer states the gem developer supplied the code he answers with.
What I feel like I need in my update method is to replace:
#friend = User.find(params[:id])
With this:
#friendship = Friendship.find_by_friend_id(params[:id])
EDIT
I can successfully request a friend, I just cannot accept or decline a friend. I a listing of users, clicking the "Add Friend" link creates the record in the friendships db correctly. If I log ins as that recently requested user and attempt to accept the request is when I get the above error. This also occurs if I attempt to decline the request.
The friends method you asked to see come with the amistad gem, here is the code for that method. As for my Ruby logs the section that displays the error was very long, so I have included it in this gist.
Given my current reputation, I can only post an answer instead of a comment to your question but as far as I can see from the controller sources you posted, you are not calling current_user.approve #friend in your update action.
I used this gem in one of my projects recently without running into any problems. The controller actions look like this:
def update
#friend = User.find_by_id(params[:id])
if current_user.approve #friend
redirect_to friendships_path, notice: t('.confirmation_successful')
else
redirect_to friendships_path, alert: t('.confirmation_unsuccessful')
end
end
def destroy
#friend = User.find_by_id(params[:id])
if current_user.remove_friendship #friend
redirect_to friendships_path, notice: t('.deletion_successful')
else
redirect_to friendships_path, alert: t('.deletion_unsuccessful')
end
end
I hope this helps.
The lookup problem is because you're passing ids inconsistently. In 3 of the links, you're passing the User object directly, which should automatically store the id in params[:id], which you can use in your action as User.find(params[:id]). But in your actions, you're extracting it from params[:user_id], which is empty. Not sure how you're getting an ID of 29 in your error message (or 32 or whatever), but...
If you change all your actions to expect params[:id] and switch the "Add friend" path link to pass in a User object the way the others already are, you should be passing the right data in the right parameter, and the lookup should straighten itself out.
Of course, as Wonky Business points out, you're not actually calling approve in your update method, so nothing will actually link, but at least you should be finding all your model objects.
As an aside, it appears from your paths you're remapping the friendship named routes to friend instead. That's muddling the issue because none of the RESTful routes are actually doing what their noun/verb combination implies: if you call friends_path(user) with a POST, there should be a new Friend object when you're done, but this controller is creating and destroying Friendship objects and leaving the Friend objects alone.
If you delete that alias and switch to friendship_path and so forth, then REST will actually be doing what it says it is: managing friendship objects.
Hope that helps!
I am trying to use amistad as a friendship gem.. But i cant get it to work correctly. I use devise as authentication system , my problem when I add click add friend link :
<% unless current_user == #user %>
<%= link_to "Arkadaşlarıma Ekle", friends_path(:friend_id => #user), :method => :post,class: "btn btn-large btn-primary" %>
<%end %>
I get couldn't find User without an ID error. I cant find the correct links.
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 create
#Friend = User.find(params[:user_id])
#friendship_created = current_user.invite(#Friend)
if #friendship_created
flash.now[:notice] = "Une demande d'amiti a t envoye #{#friend.fullname}"
end
end
def approve
#Friend = User.find(params[:user_id])
#friendship_approved = current_user.approve(#Friend)
#friends = current_user.friends
#pending_invited_by = current_user.pending_invited_by
flash.now[:notice] = "La demande d'amiti de #{#friend.fullname} a t approuve"
end
def remove
#Friend = User.find(params[:user_id])
#friendship = current_user.send(:find_any_friendship_with, #Friend)
if #friendship
#friendship.delete
#removed = true
flash.now[:notice] = "Artık #{#friend.fullname} ile arkadaşsınız"
end
end
end
Thank you for your answers.
You can't send HTTP POST requests through normal links (without triggering AJAX requests). Replace the link with a form, either manually created through form_for and the like, or generated with button_to.
I fixed it. I had to use friends_path(:user_id => #user), instead of friends_path(:friend_id => #user),
I still need a good way to solve amistad views.