Rails, send params to controller action through link_to - ruby-on-rails

Is it safe/acceptable to send params this way to create action in the controller? Is there any potential problems?
<%= link_to "Acceptance", acceptances_path(acceptance: {favor_id: #favor.id, user_id: current_user.id}), method: :post %>
and then in controller
class AcceptancesController < ApplicationController
def create
#acceptance = Acceptance.new(acceptance_params)
if #acceptance.save
redirect_to favors_path
else
render :template => 'favors/index'
end
end
private
def acceptance_params
params.require(:acceptance).permit(:favor_id, :user_id)
end
end
Thanks for your time in advance!

The best (and the safest) you could do is assigning these id's in controller.
Since you have access to #favor and current_user objects, you'd be better of doing this:
def create
#acceptance = Acceptance.new(acceptance_params)
#acceptance.favor_id = #favor.id
#acceptance.user_id = current_user.id
# code omitted
end

Related

Passing instance variable from controller to view in rails

I have a user profile controller called "userinfo" and it's corresponding view. The userinfo index is the root path. In the homepage(which is the userinfo index), I have a link that takes you to the user profile page. It is giving me this error when I click on the image on the view page:
My routes are:
My userinfos_controller:
class UserinfosController < ApplicationController
before_action :find_userinfo, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#userinfors = Userinfo.where(:userinfo_id => #userinformation_user_id)
end
def show
#myvideo = Video.last
end
def new
#userinformation = current_user.userinfos.build
end
def create
#userinformation = current_user.userinfos.build(userinfo_params)
if #userinformation.save
redirect_to root_path
else
render 'new'
end
end
def edit
end
def update
end
def destroy
#userinformation.destroy
redirect_to userinfo_path
end
private
def userinfo_params
params.require(:userinfo).permit(:name, :email, :college, :gpa, :major)
end
def find_userinfo
#userinformation = Userinfo.find(params[:id])
end
end
and my view is:
<%= link_to image_tag("student.png", class: 'right'), userinfo_path(#userinfors) %>
I thought maybe I must include ':index' in the 'before_action :find_userinfo' at the top of my controller. If I do that, the homepage doesn't even load and it gives me this error:
Try below code:
controller
def index
#userinfors = Userinfo.where(:userinfo_id => #userinformation_user_id) #pass id instead of object #userinformation_user_id
end
view
<% #userinfors.each do |u| %>
<%= link_to image_tag("student.png", class: 'right'), userinfo_path(u) %>
<% end %>
Your problem is that you're trying to do perform a lookup based on something that's not an ActiveRecord (database) attribute.
Your root goes to UserinfosController which expects #userinformation_user_id but I can't tell from your code where that comes from.
You need to define your route in order that this will be expecting for an specific param, maybe the user id, and then you're able to add the value within your view, in a link_to helper:
You could modify your routes.rb to expect an id as param:
get '/user_infors/:id', to: 'userinfos#index', as: 'userinfo_path'
Then in your controller, use a find to "find" in the database the user with such id. If you'd like to use where then that would give you a relationship with all the userinfos with the id being passed as param.
If you want so, then use Userinfo.where('userinfo_id = ?', params[:id]):
def index
#userinfors = Userinfo.find(params[:id])
end
And then in your view you can access to #userinfors:
<% #userinfors.each do |user| %>
<%= link_to image_tag 'student.png', class: 'right', userinfo_path(user) %>
<% end %>
I think you could define the index to get all the userinfors and a show method to get an specific one, as you're trying to do.

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?

Passed params drop after failed submit

In my app I pass parameters from one controller to another
Firstly I'm creating Company object and pass its id in parameters in redirecting link
companies_controller:
class CompaniesController < ApplicationController
def new
#company = Company.new
end
def create
#company = current_user.companies.build(company_params)
if #company.save
redirect_to new_constituent_path(:constituent, company_id: #company.id)
else
render 'new'
end
end
private
def company_params
params.require(:company).permit(:name)
end
end
After successfully Company saving I'm redirected to creating a Constituent object. I fill company_id or entrepreneur_id with parameters passed in link http://localhost:3000/constituents/new.constituent?company_id=9 for example
constituents/new:
= simple_form_for #constituent do |f|
= f.input :employees
- if params[:entrepreneur_id]
= f.hidden_field :entrepreneur_id, value: params[:entrepreneur_id]
- elsif params[:company_id]
= f.hidden_field :company_id, value: params[:company_id]
= f.button :submit
constituents_controller:
class ConstituentsController < ApplicationController
def new
#constituent = Constituent.new
end
def create
#constituent = Constituent.create(constituent_params)
if #constituent.save
redirect_to root_url
else
render 'new'
end
end
private
def constituent_params
params.require(:constituent).permit(:employees, :company_id, :entrepreneur_id)
end
end
The problem is parameters I passed in link is dropping after failed attempt to save #constituent and company_id or entrepreneur_id is nil. How can I fix it?
This happens because after you submit your form, there are no params[:company_id] = 9 anymore. After render :new is done, you will have params[:constituent][:company_id] = 9.
So, to solve this problem, you need to send not this get request to new Constituent:
http://localhost:3000/constituents/new?company_id=9
But something like this:
http://localhost:3000/constituents/new?constituent[company_id]=9
Your view will become a little bit more ugly, to avoid error if params[:constituent] not exist:
- if params[:constituent]
- if params[:constituent][:entrepreneur_id]
= f.hidden_field :entrepreneur_id, value: params[:constituent][:entrepreneur_id]
- elsif params[:constituent][:company_id]
= f.hidden_field :company_id, value: params[constituent][:company_id]

Could find Addict without an ID

I'm trying to put a new form that creates new "Addicts" in a modal in my home page.
It's a simple form with 2 inputs, that when clicking on New, a modal pops up with that form in my index page.
I can't get it to work because it keeps saying "Couldnt find Addict without an ID".
My Pages Controller
class PagesController < ApplicationController
def home
#addict = Addict.find(params[:id])
#lanzaderas = Lanzadera.all
render 'index'
end
end
My Addict Controller
class AddictsController < ApplicationController
def index
#posts = Addict.all
end
def show
#addict = Addict.find(params[:id])
end
def new
#addict = Addict.new(params[:addict])
end
def create
#addict = Addict.new(params[:addict])
if #addict.save
redirect_to posts_path, :notice => "Your Addict was saved"
else
render "new"
end
end
def edit
end
def update
end
def destroy
end
end
end
My form in my modal
<%= form_for #addict do |f| %>
<%= f.input :name %>
<%= f.input :surname %>
<%= f.input :postal %>
<%= f.submit %>
<% end %>
I know it has something to do with the variable / id not being passed correctly in my Controller, but it's an error I get lots of times and don't know why I happens.
Thanks!
In def home in your PagesController you have this code:
#addict = Addict.find(params[:id])
I suspect, that you don't have the id for 'addict' in your parameters, when you visit your home action.
Do you want to display one particular addict in your 'home' page? If not, you can remove this line.
Update:
Change this in your AddictsController:
def new
#addict = Addict.new
end
In the new action you only "prepare" a new addict object. Using the find method is not possible, since the record hasn't been created yet.
If you're using Rails 4 you also have to permit your parameters (for security reasons; more info here: Railsguides: Strong Parameters)
In your case you have to do 2 things:
First: add this at the bottom of your AddictsController:
private
def addict_params
params.require(:addict).permit(:name, :surname, :postal)
end
Second: use this method in your create action instead of params[:addict]:
def create
#addict = Addict.new(addict_params)
if #addict.save
redirect_to posts_path, :notice => "Your Addict was saved"
else
render "new"
end
end

Is creating a new model by passing it params secure?

I have a comment model. I am creating a new instance of that model by passing it params from my view to the comment controller. Here is the comment controller:
class CommentsController < ApplicationController
def create
session[:return_to] = request.referrer
#comment = Comment.create(:user_id => current_user.id,
:issue_id => params[:issue_id],
:content => params[:content])
redirect_to session[:return_to]
end
end
Here is how I am passing the params in my view:
<%= link_to "Test Comment", comments_path(:issue_id => #issue.id,
:content => "HeLLO"),
method: :create %>
my question is - is this secure? What prevents someone from changing the params[:issue_id] and commenting on another issue? Is there a better way of doing this?
yeah, there are better ways
at first we look to your controller. to store the referrer and redirect back to it makes no sense (at least you should NOT save this in a session) rails can do this with the key :back.
at second you dont need to make a varaible with the # because you dont use the created object. and also you dont need to save the restult. just do
class CommentsController < ApplicationController
def create
Comment.create(:user=>current_user, :issue_id=>params[:issue_id],:content=> params[:content])
redirect_to :back
end
end
++ edit
actually a better way would to to it like this:
class CommentsController < ApplicationController
def create
current_user.comments.create(issue_id: params[:issue_id], content: params[:content])
redirect_to :back
end
end
just use rails associations
-- edit
and as you think, YES we can change the issue_id and write comments to any issue i want. so if you want to protect from this you have do do a helper before you crate a comment (its just an example)
class CommentsController < ApplicationController
def create
issue = Issue.find(params[:issue_id]
if issue.is_locked? || current_user.cant_write_at_issue(issue)
return redirect_to :back, :notice=>"You dont have Privilegs"
end
issue.comments.create :user=>current_user, :content=>params[:content])
redirect_to :back :notice=>"Comment was created successfully"
end
end
is_locked and cant_write_at_issue you need to define in your models. this is just a way how to protect something.
so now we can change the issue ID but you look if the user has access for doing this :-)

Resources