Get any id to any user exists in the database - ruby-on-rails

I am new to rails and have a task that asks me to send an invitation for any user to be admin in my magazine here is my piece of code
def invite
inviteUser = { 'user_id' => current_user.id, 'Magazine_id' => params[:id] }
CollaborationInvitation.create(inviteUser)
#magazine = Magazine.find(params[:id])
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to root_path
end
I need to replace current_user.id with something that refers to any user's id which exists in my database to send him an invitation to be admin with me I tried to add #User=Users.All and then pass it as a variable but it got me an error I tried a lot of things but every time I get an error except for adding current_user.id
ps: I am using devise for authentication

You asked a couple things, and it is kind of confusing what you want to do.
Here is how you get all ids of records in a model.
Rails4: User.ids
Rails3: User.all.map(&:id)
Or (not sure if #pluck is in Rails 3 or not)
User.pluck(:id)
If you want to get a random user (you mentioned "any user") you could do.
User.find(User.pluck(:id).sample)
Though I think what you really want to do is to pass the id or some other attribute of a user as a param to the action and send that user an invitation.
Presumably you either have a post or get route for "users#invite" (the action you wrote in your question). You can add a named parameter there or you can pass a url param or if you are using a post route, you could add the param to the post body.
Then in your contoller you can do something like this (I'll use email as an attribute):
def invite
#user = User.find_by(email: params[:user_email])
#Rails 3 like this
# #user = User.find_by_email(params[:user_email])
# now do stuff with user
end

User.all will return you the collection of users. So,
Find the user object to get an id...
Try this code....
def invite
inviteUser = { 'user_id' => User.find_by_email('user#example.com').id, 'Magazine_id' => params[:id] }
CollaborationInvitation.create(inviteUser)
#magazine = Magazine.find(params[:id])
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to root_path
end

You can try
User.last.id
or
User.find_by_email("xyz#test.com").id
or
User.where(email: "xyz#test.com").first.id
Replace xyz#test.com with desired user email address. To get more details on rails active record query interface, please read rails guides http://guides.rubyonrails.org/active_record_querying.html

Related

How to look check whether model exists and create if it doesn't with a single form?

I'm trying to implement a form with the following behavior:
1) Input some semantic data about a user (i.e. username).
2) Do a User.find_by(:username = username).
3) If such a user exists, direct to show page for that user.
4) If such a user does not exist, create a new user with the provided username, then redirect to the show page for that user.
This should be simple but I cannot figure out how to format the form_for helper and my show and create actions in my user_controller to implement this behavior.
I currently have:
form_with :url => 'users/:id', :method => :get do
...
end
because I'm ultimately trying to invoke the "show" method of the controller. However, my form does not take in a user's id as a parameter, and when the user does not yet exist there is no :id parameter to access at the time of the form's submission.
How can I set up my form to redirect to show in each case, while still adhering to the logic explained above?
You can do something like this in your User's Controller create action
def create
usr_name = params[:username]
#user = User.where(username: usr_name).first_or_initialize
if #user.persisted?
redirect_to user_path(#user) # or whatever your user show path is
elsif #user.save
redirect_to user_path(#user)
else
render :new
end
end
You would just need to make sure that you are validating the uniqueness of usernames.
Also, first_or_initialize(and its counterpart first_or_create) can take in a block. So, you can assign other attributes to the new User like this...
User.where(username: usr_name).first_or_initialize do |usr|
usr.some_attribute = some_value
end
you can use find_or_initialize_by(unique_key) in your create method.unique_key can be any key which you are using to identify your user such as email,phone etc.

Is there a way to get the visitors city and country in Rails controller?

In my current app, i use Geocoder gem to get the city and the country of the visitor. I use hidden fields in my view to get these details. When the login form is submitted, these details will be sent to the controller and the controller will save them to the database. When I try to get these details directly from the controller by using
request.location.city
It will assigning a blank value to the database. If I use hidden fields in the view, some one can temper with them right? So, how can I fix this?
You should store visitor information before you render any content:
class UsersController
def new
# I suspect that, for fast insert, you should probably use a NoSQL database
# to perform `store!` or even just write it to a log file
Visitor.store!(:city => request.location.city, :ip => request.ip)
end
def create
#user = User.build(params[:user].merge(:city => request.location.city))
if #user.valid?
#user.save
flash[:notice] = "You've been registered!"
redirect_to user_dashboard_path
else
flash[:notice] = "Couldn't register your account"
render action: "new"
end
end
end

NoMethodError in ConfirmationController

I have been trying to solve the following problem for a couple of days. Forgive me if this is a common problem as I am new to rails and probably couldn't query the right question/keyword in stackoverflow or google.
I am building a system where a user will get an invite via email, click on a unique link, be taken to a page where he/she can accept or decline the invitation. I am getting stuck at the part where the user accepts or declines the invitation.
I've built it around two controllers: an invitations controller and a confirmations controller.The invitations controller creates a record containing a name, an email, and a uniquely generated token. The controller then emails a link with the token to the defined email. The link points to the confirmations controller and passes the unique token from the invitation. However, when clicking on the link and accepting the invitation, I get the following error:
NoMethodError in ConfirmationController#confirm
undefined method `update_attribute' for nil:NilClass
Here is some of the code for solving this issue:
Confirmation_controller.rb
class ConfirmationController < ApplicationController
def new
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
end
def confirm
if #confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end
end
routes.rb
match '/confirmation/:invite_token', to: 'confirmation#new'
match '/confirmation/:invite_token/confirm', to: 'confirmation#confirm'
app/views/confirmation/new.html.erb
Click here to accept:
<%= link_to "Confirm", :controller => "confirmation", :action => "confirm" %>
You need to get your Invitation in the confirm method too.
If you want rails to raise an exception if no invitation was found
def confirm
#confirmation = Invitation.find_by_invite_token!(params[:invite_token])
#confirmation.update_...
end
No exception will be raise. You may want to check manually with a condition in the following case.
def confirm
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
if #confirmation
#confirmation.update_...
else
# do something
end
end
You should find confirmation record before calling update_attribute on it, like you did it in new action:
#confirmation = Invitation.find_by_invite_token(params[:invite_token])
Or, to throw exception when the record is not found and to render 404 page to the user:
#ocnfirmation = Invitation.find_by_invite_token!(params[:invite_token])
The problem is that you never told the program what #confirmation is. What you should do is find it first then run the update. Note this is different from the different answers, just thought I would throw in some variety.
def confirm
# You're missing this line below. Basic search for the confirmation.
# Note too that you will have to pass in the parameter `invite_token` for it to work
# I'm also assuming invite_token is unique among each invitation
confirmation = Invitation.where(invite_token: params[:invite_token])
# Notice that I'm first checking to see if the confirmation record exists, then doing an update
if confirmation and confirmation.update_attribute(:accepted, true)
flash[:success] = "Invitation confirmed!"
redirect_to 'static_pages/home'
else
flash[:notice] = "Failed :("
redirect_to 'static_pages/home'
end
end

updating user review in Ruby on Rails

Hi i was wondering if there was a way a user can update a review they have already written, i tried using cancan but ran into a few problems so i rather find out if there is an easier way. This is code from the 'new' method in the reviews controller
def new
if logged_in?
#review = Review.new(:film_id => params[:id], :name =>
User.find(session[:user_id]).name)
session[:return_to] = nil
else
session[:return_to] = request.url
redirect_to login_path, alert: "You must be logged in to write a review"
end
end
and the 'create' method
def create
# use the class method 'new' with the parameter 'review', populated
# with values from a form
#review = Review.new(params[:review])
# attempt to save to the database, the new review instance variable
if #review.save
# use the class method 'find' with the id of the product of the
# saved review and assign this product object to the variable 'product'
film = Film.find(#review.film.id)
# redirect the reviewer to the show page of the product they reviewed,
# using the product variable, and send a notice indicating the review
# was successfully added
redirect_to film, notice: "Your review was successfully added"
else
# if the review could not be saved, return / render the new form
render action: "new"
end
end
i want the user to edit their review if they have already written a review for a product. Instead of having two reviews from the same user for the same product.
You could potentially sub something like this into the create method:
# Assumes that your user names are unique
#review = Review.find_or_create_by_film_id_and_name(params[:review][:film_id], User.find(session[:user_id]).name)
#review.update_attributes(params[:review])
This does the following
Checks whether the user has created a review for the film
If yes, assigns the existing review to the #review instance variable
If not, creates a new Review object and assigns it to #review
Updates #review with params[:review]
Alternatively, the following statements will accomplish the same without using the Rails find_or_create convenience method:
user_name = User.find(session[:user_id]).name # To avoid two DB lookups below
#review = Review.find_by_film_id_and_name(params[:review][:film_id], user_name) || Review.new(:film_id => params[:review][:film_id], :name => user_name)
#review.update_attributes(params[:review])
To update a record, you should use the update action, which is requested after the user submitted the edit form.
Make your User model have has_many/has_one :reviews. And Review model belongs_to :user. And then if you have any kind of authorization(and you should have, for ex: devise) you'll know if user of review is currently logged user. If so then render edit button, otherwise not render.
Also according to CRUD conventions, there are 2 actions you need. First its edit and other one update. You can read about it on railsguides.com

Masking controllers functions -- Rails3

I would like to hide or mask example.com/users/$ID/edit to be example.com/profile/edit.
config/routes.rb
resources :users
app/controllers/users_controller.rb
def edit
#user = User.find(params[:id])
end
I've tried adding the route
match '/profile/edit' => 'users#edit', :as => :edit_profile
but, when I visit example.com/profile/edit, the edit method complains about not being able to find the user's ID.
Is there a way I can mask the ID from the browser?
If you're trying to edit the current user's profile you could use the following in your edit action:
def edit
#user = User.find_by_id( params[:id] ) || current_user
end
This will first try to look up the user by the id parameter returning nil if it can't find the user and if the return value is nil it will set #user to the return value of the current_user helper method. This assumes you're using something like Devise which provides the current_user method to get the currently logged in user.
One other note. You should change match in your route to get to specify that only get requests are valid for the edit action.
get 'profile/edit' => 'users#edit' , as: edit_profile
If you're trying to prevent users from editing other people's profiles you need something like the following after you load the user:
redirect_to( root_path ) and return unless #user == current_user
This will keep the current user from editing another user's profile.
If you want to allow logged in user to change it's profile, maybe you'll want to store user's id in the session.
So when user logs in you save it's ID into the session:
session[:user_id] = ...
Then your edit method will look like
def edit
#user = User.find(session[:user_id])
end
If that solution is not what you want, than you maybe will just need to add the ':id' parameter to the match code.

Resources