Rails Create article with other user not current_user - ruby-on-rails

I would like to create an article with other user not current_user and for that I'm saving in a session the id to the other user and I recover this id with a collection in the view to this point everything work fine but when I'm trying to use my helper :selected_user into my articles controller with a if sentence doesn't work here is my code:
def new
if selected_user.present?
#article = selected_user.articles.build state: :step1
render_wizard
else
#article = current_user.articles.build state: :step1
render_wizard
end
end
so, I'm asking if the selected_user.present? I would like to create the article with this user_id but else I would like to create it with the current_user
my create method is:
def create
if selected_user.present?
step = :step1
#article = selected_user.articles.build article_params_step1
#article.state = step.to_s
if #article.save
redirect_to wizard_path(next_step, article_id: #article)
else
render_wizard
end
else
step = :step1
#article = current_user.articles.build article_params_step1
#article.state = step.to_s
if #article.save
redirect_to wizard_path(next_step, article_id: #article)
else
render_wizard
end
end
end
so, yeah when I run my view the controller jump to the else section.
just for clarify my selected_user not return nil but here is the implementation:
selections_controller.rb:
class SelectionsController < ApplicationController
before_action :authenticate_user!
def create
session[:selected_user_id] = params[:user][ :user_id]
redirect_to root_path
end
end
and in my application_controller.rb:
helper_method :selected_user
def selected_user
#selected_user ||= User.find(session[:selected_user_id])
end
and in the view:
<%= form_tag( { :controller => "selections", :action => "create" } , :class => "navbar-form navbar-left") do %>
<%= collection_select(:user, :user_id, User.all, :id, :name, prompt: "Escoge cliente")%>
<%= submit_tag 'Enviar' %>
<% end %>
if I try create an article without select an user from my collection appear this error:
Couldn't find User with 'id'=
but when I select my user from the collection everything works fine. so just I want when I don't select nothing create with the current_user.
Thanks for your time !
Regards !

The reason why you were seeing the error
Couldn't find User with 'id'=
when you haven't selected a user was that the session[:selected_user_id] was nil and your old selected_user with following code was throwing the error.
def selected_user
#selected_user ||= User.find(session[:selected_user_id])
end
User.find method expects either a single id or an array of ids. If you give a single id and if it finds the relevant record in the database then it will returns that instance. If you give an array of ids and if it finds those relevant records in the database, then it will return array of those instances. But if you pass nil to it, then it will through the error Couldn't find User with 'id'= as it won't find a relevant record.
But your updated selected_user implementation:
def selected_user
#selected_user ||= session[:selected_user_id] && User.find_by_id(session[:selected_user_id])
end
is working because, first you are checking for the existence of session[:selected_user_id] value and second you are using User.find_by_id instead of User.find.
User.find_by_id either returns a single instance of the record if it finds it in the database or will return nil if it doesn't find the record. It will never through an error.
Refer to ActiveRecord#find and ActiveRecord#find_by for more info.

I'm not sure why is working and what is the different but my solution for the problem it was to add this to my selected_user method:
def selected_user
#selected_user ||= session[:selected_user_id] && User.find_by_id(session[:selected_user_id])
end
and with that I don't have the nil error and entry to the if statement without errors.

Related

Ruby on rails get id from instance variable

I have an instance variable #user
so in HTML <%=link_to #user %> gives me the result:
{"id"=>2, "restaurant"=>"sea food", "password"=>"123", "name"=>"a", "email"=>"a", "telephone"=>"123", "created_at"=>"2016-10-09T04:00:24.010Z", "updated_at"=>"2016-10-09T04:00:24.010Z"}
I want to get the value of id, but when I write:<%=link_to #user[:id] %> it returns me the result :/restaurant/home, which is the route of my home function inside my restaurant controller and I can't understand why.
This is my controller:
class RestaurantController < ApplicationController
def home
#user = session['loginedUser']
end
def login
end
def checkLogin
#user = User.find_by_restaurant(params[:user][:restaurant])
if #user != nil && #user[:password] == params[:user][:password]
session['loginedUser'] = #user
redirect_to :controller=>'restaurant',:action=>'home'
else
session['loginedUser'] = nil
# redirect_to :controller=>'restaurant',:action=>'login'
end
end
def logout
session['loginedUser'] = nil
redirect_to :controller=>'restaurant',:action=>'home'
end
end
Can anybody help?
Thanks a lot.
You should not save complex objects within your session object. Session data is saved within a cookie by default and many browsers accept only cookies until 4kB. Other issues exists too.
I suggest this change:
def checkLogin
...
session['loginedUser'] = #user.id
...
end
def home
#user = User.find session['loginedUser']
end
Your link to should look like this
<%=link_to id: #user.id %>. This solution is not realy Rails like. There should be an appropriate helper. You can check your routes with rake routes | grep home. You will see something like xxx_xxx_home_xxx_restaurant /restaurant/home(.format) restaurant#home. The first part is the helper name and you can add _path or _url. This may look like <%=link_to xxx_xxx_home_xxx_restaurant_path id: #user.id %>

Ruby on rails. Passing params from view to controller

I'm having what I assume must be a simple problem but I just can't figure it out. I'm trying to update an attribute in one model when another is created.
In my view:
<%= link_to 'Click here to rate this user', new_user_review_path(:user_id => request.user.id, :gigid => request.gig.id), remote: true %>
Which passes params :gigid and :user_id
Than my controller:
def new
#review = Review.new
#gig = Gig.find(params[:gigid])
end
def create
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
#gig.update(reviewed: true)
respond_to do |format|
format.html {redirect_to session.delete(:return_to), flash[:notice] = "Thankyou for your rating!"}
format.js
end
else
render 'new'
end
end
But I get undefined method 'update'for nil:NilCLass:
I know the params are passing and the 'Gig' can be updated as :
def new
#review = Review.new
Gig.find(params[:gigid]).update(reviewed: true)
end
updates the attribute fine, but when I click 'New review' not when the review is actually created.
Adding :
def create
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
Gig.find(params[:gigid]).update(reviewed: true)
etc etc etc
gives me the same undefined method 'update'for nil:NilCLass:
I have tried with find_by_id instead of find which makes no difference.
EDIT:
def create
#gig = Gig.find params[:gigid]
#review = #user.reviews.new review_params
#review.reviewed_id = current_user.id
if #review.save
#gig.update(reviewed: true)
etc etc etc
Doesn't work either. I get no errors, but the gig ID is still 'nil'.
The params are passing to the 'New' action but not the 'Create' action. I feel this should be very easy but I'm just not seeing it at the moment.
But I get undefined method 'update'for nil:NilCLass:
The error is that you have not defined #gig in your create action.
Since Rails is built on HTTP, and HTTP is stateless, you have to set the "instance" variables with each new request:
def new
#review = Review.new
#gig = Gig.find params[:gigid]
end
def create
#gig = Gig.find params[:gigid]
#review = #user.reviews.new review_params
A much better pattern for you would be to use the after_create callback in your Review model:
#app/models/review.rb
class Review < ActiveRecord::Base
belongs_to :gig #-> I presume
after_create :set_gig
private
def set_gig
self.gig.update(reviewed: true)
end
end
--
If you wanted to make the Gig update within your current setup, you'll be best sending the gig_id param through the request (not the link):
#app/views/reviews/new.html.erb
<%= form_for [#user, #review] do |f| %>
<%= f.hidden_field :gig_id, #gig.id %> #-> params[:reviews][:gig_id]
...
<% end %>
This will make params[:review][:gig_id] available in the create action, with which you'll be able to use in your code.
The problem is, you never assigned a value to #gig in your create method. I can't see your form, but you need something like this in your create method:
#gig = Gig.find params[:gigid]
Assuming that you're passing the parameter :gigid to #create
In the second example you showed, I'm not sure what's going on, but you should be getting a ActiveRecord::RecordNotFound exception on the find().
Try the below code for update operation.
gig_record = Gig.find_by_id(params[:gigid])
gig_record.update_attribute(reviewed: true) unless gig_record.blank?

Rails Two Views With One Controller#Action

I created a rails association "user has many follows" currently have lists of user's followers and followings. I want to have 2 links onusers#show to display lists of followers and followings. I know I can render two different views in my follows#index using if else statement but I'm not sure how to go about it. My initial thought was to have rails check which link was clicked (either 'Followers' or 'Followings') but I couldn't find an exact answer. I also thought of creating two different tables (Followers, Followings) but adding 2 same values for 1 action seemed redundant and waste of space.
Here is my FollowsController:
class FollowsController < ApplicationController
def index
#follows = Follow.all
render :index
end
def create
#follow = Follow.create(follow_params)
redirect_to user_url(#follow.user_id)
end
def destroy
#follow = Follow.find(params[:id])
#follower_id = #follow.user_id
#follow.destroy!
redirect_to user_url(#follower_id)
end
private
def follow_params
params.require(:follow).permit(:follower_id, :user_id)
end
end
What would be the best approach?
Example:
def index
#follows = Follow.all
if #follows.present?
render 'show_with_followers'
else
render 'show_without_followings'
end
end
views
app/views/follows/_show_with_followers.html.erb
app/views/follows/_show_without_followings.html.erb
Here is an answer I found so far. I will be using in my view
<%= link_to 'Followers', follows_path(:follows => 'followers') %>
<%= link_to 'Followings', follows_path(:follows => 'followings') %>
and use
def index
if params["follows"] == 'followers'
#render followers
else
#render followings
end
end
end

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 parameters into model

Rails 3.0.3
ruby 1.9.2p0
The Problem:
I have a Users table which has many items, the item(s) in turn therefore belongs to the Users.
In my model item.rb i attempt to save the item along with the value for the user.id so i have:
self.User_ID = #user.id
this however give me the error
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
this is causing some confusion that it can't find this as in the show.html.erb that 'wraps' this page <%= #user.id %> displays the correct ID on the page
Many thanks in advance
** EDIT **
The Shorten action is the action upon which i want to parameter to be passed
class ItemsController < ApplicationController
def redirect
#item = Item.find_by_shortened(params[:shortened])
if #item
#redirect_to #item.original
redirect_to #item.original
else
redirect_to :shorten
end
end
def shorten
#host = request.host_with_port
#user = current_user
You need to load the #user model in every action that will require access to it. Having it render properly in the show action will not guarantee it is loaded in the update action.
Usually you need to have something like this in your controller:
class UsersController < ApplicationController
before_filter :load_user, :except => [ :index, :new, :create ]
# ...
protected
def load_user
#user = User.find(params[:user_id] || params[:id])
rescue ActiveRecord::RecordNotFound
render(:text => 'Record not found')
end
end

Resources