Can't unfollow user because of Postgres - ruby-on-rails

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

Related

simple_form_for how to pass params to controller

I want to pass params from event/id(show page) to my order_controller.
I use simple_form_for to pass event.id and promocode that input by user
#event.show.html.haml
= simple_form_for order_url, url: orders_path(#event, :promocode), method: :post do |f|
= f.hidden_field :event_id, params: {id: #event.id}
= f.input :promocode, value: :promocode, class: 'form-control', placeholder: "Enter your PromoCode"
= f.submit 'APPLY PromoCode'
IDK if a need hidden_field to pass event_id
#order_controller
class OrdersController < ApplicationController
before_action :order, only: %i[show]
def index
#orders = Order.all.order(created_at: :desc).page(params[:page]).per(5)
end
def show; end
def create
#order = Order.create(title: event.title, user_id: current_user.id, event_id: event.id, order_amount: event.price, order_currency: event.currency)
if !promo.nil?
redirect_to_order
elsif #order.save
redirect_to checkout_create_path(id: #order.id)
else
redirect_to event, alert: 'Something went wrong, try again later'
end
end
def redirect_to_order
promo_validate
order_amount_promo_code = #order.order_amount - promo.promo_code_amount
order.update(order_amount: order_amount_promo_code)
redirect_to #order
end
def promo_validate
if promo.present? && promo.promo_code_amount.positive? && promo.promo_code_currency == event.currency
promo.update(order_id: #order.id)
else
redirect_to event, alert: "This PromoCode is invalid or Your PromoCode Currency doesn't match with Event"
end
end
private
def promo
#promo ||= PromoCode.find_by(uuid: params[:promocode])
end
def event
#event ||= Event.find(params[:id])
end
def order
#order ||= Order.find(params[:id])
end
def order_params
params.require(:order).permit(:title, :event_id, :promocode, :event)
end
end
I'm using methods def event and def promo to take this params from view.
Also my routes look like this.
resources :events
resources :orders
I would nest the route:
resources :events do
resources :orders, shallow: true
end
This creates an explicit relationship between the two resources that can be seen by just looking at the URL. To create a order tied to an even you send a POST request to /events/:event_id/orders.
class EventsController
def show
# ..
#order = #event.orders.new
end
end
= simple_form_for [#event, #order] do |f|
= f.input :promocode, value: :promocode, class: 'form-control', placeholder: "Enter your PromoCode"
= f.submit 'APPLY PromoCode'
class OrdersController < ApplicationController
# POST /events/:id/orders
def create
#event = Event.find(params[:event_id])
#order = #event.orders.new(title: #event.title, user: current_user order_amount: #event.price, order_currency: #event.currency)
begin
#promo = PromoCode.find_by!(uuid: params[:order][:promocode])
rescue ActiveRecord::RecordNotFound
#order.errors.add(:promocode, 'is invalid')
end
if #order.save
redirect_to checkout_create_path(id: #order.id)
else
redirect_to #event, alert: 'Something went wrong, try again later'
end
end
# ...
end
Other then that your handling of promo codes is very iffy. Instead of monkying around and deducting the rebate from the "amount" by updating the record you should store both the original sales price and the rebate and then calculate the total at checkout - which should also be stored separately. Not doing so amounts to pretty dismal record keeping and might get you in trouble - when it comes to money always play it safe.

Destroying Friendship in Ruby on Rails

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)

How to add a member to team with email_field_tag

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.

Update attributes separately in Rails

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

Passing Values to Controllers

I'm trying to allow users to 'favorite' links (that is, create a new Favorite record with their user_id and the link_id) This is what I have so far..
When I click favorite (as a user), the new record is assigned to the user_id but the link_id field is nil. How can I pass the link_id into my FavoritesController?
My View Code
Added Link Model Code
class FavoritesController < ApplicationController
def create
#user = User.find(session[:user_id])
#favorite = #user.favorites.create :link_id => params[:id]
redirect_to :back
end
end
The Favorite model belongs to :user and :link
Note: I've also tried this but when I click 'favorite', there's an error "Couldn't find Link without an ID."
Update
<%= link_to "Favorite", :controller => :favorites, :action => :create, :link_id => link.id %>
with
class FavoritesController < ApplicationController
def create
#user = User.find(session[:user_id])
#favorite = #user.favorites.create :link_id => :params[:link_id]
redirect_to :back
end
end
Returns "can't convert Symbol into Integer"
app/controllers/favorites_controller.rb:4:in []
app/controllers/favorites_controller.rb:4:in create
I've tried forcing it into an Integer several ways with .to_i
You could try the following
In your view:
<%= link_to "Favorite", :controller => :favorites, :action => :create, :link_id => link.id %>
In your controller:
class FavoritesController < ApplicationController
def create
#user = User.find(:first, :conditions => ["id = ?", session[:id]])
#favorite = #user.favorites.create
#favorite.update_attributes(:link_id => params[:link_id])
redirect_to :back
end
end
Just as a side note, when finding records, i tend to use:
.find(:first, :conditions => ["id = ?", session[:id]])
as it will escape most stuff submitted by user and returns one record.
I have broken the steps up in your controller, but you could combine them into one like this:
def create
#user = User.find(:first, :conditions => ["id = ?", session[:id]])
#favorite = #user.favorites.create(:link_id => params[:link_id])
redirect_to :back
end
hopefully that should work
You should try:
#user = User.find(session[:user_id])
#favorite = Favorite.create :link_id => params[:id]
#favorite.user = #user
It fails because params[:id] is nil. Put
throw params
at the beginning of the create method and check what you have available there. Please psot also the code in your view.

Resources