Show username when posting comments in Rails - ruby-on-rails

I have an app when users post album reviews called Pins. I created a comments model for other users to comment on the reviews. I'm struggling getting the comments to say "Posted by" and then show the user's name who posts them. Here is some of the code:
The pins model has_many :comments
The user model has_many :comments
The comments model belongs_to :pin
belongs_to :user
Here's the comments controller:
def create
#pin = Pin.find(params[:pin_id])
#comment = #pin.comments.create(params[:comment])
#comment.username = current_user
respond_to do |format|
if #comment.save
format.html { redirect_to #pin, notice: 'Comment was successfully created.' }
format.json { render json: #comment, status: :created, location: #comment }
else
format.html { render action: "new" }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
Here is the app as it is now:
http://powerful-reaches-7038.herokuapp.com
I've tried some of the other answers posted on Stack Overflow, but no dice. I'm trying to say something like:
<strong>Posted <%= time_ago_in_words(comment.created_at) %> ago by <%= comment.user.name %></strong>

You are assigning a User instance to the username field for the Comment. I assume that the username attribute is a string in the database. So if you want the name to appear in the comment then you need to assign it the name from the current user.
So:
#comment.username = current_user.name
If you already have an association between Comment and User then you could do:
#comment.user = current_user
<%= #comment.user.name %>

You save the username in
#comment.username = current_user
and show it with:
<%= comment.user.name %>
but it have to be
<%= comment.username %>

Related

Form hidden fields and security

I m using hidden field in my app to add user_id to my database "Camping". I have associations "User" has many campings and "Camping" belongs_to "user".
When I run firebug or something like this, I can modify user_id value of this field. If any user puts his ID, I can modify object to other user... I want to avoid this !
My code
<%= f.hidden_field :user_id, :value => current_user.id %>
This code, is necessary because I allow only user to edit / updated / create object if they have user_id == current_user.id.
How to fix this security problem ?
By the way, I m using devise.
Edit with full code
My _form.html.erb
<%= form_for(camping) do |f| %>
<% if camping.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(camping.errors.count, "error") %> prohibited this camping from being saved:</h2>
<ul>
<% camping.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :user_id, :value => current_user.id %>
<div class="form-group">
<label for="name">Nom du camping</label>
<%= f.text_field :name, autofocus: true, class:"form-control", id:"name", :required => true%>
</div>
<div class="actions">
<%= f.submit "Enregistrer", class:"btn btn-success" %>
</div>
<% end %>
my controller
def new
#camping = Camping.new
#campings = Camping.all
end
def edit
end
def create
#camping = Camping.new(camping_params)
respond_to do |format|
if #camping.save
format.html { redirect_to #camping, notice: 'Camping was successfully created.' }
format.json { render :show, status: :created, location: #camping }
else
format.html { render :new }
format.json { render json: #camping.errors, status: :unprocessable_entity }
end
end
end
def update
#camping = Camping.find(params[:id])
respond_to do |format|
if #camping.update(camping_params)
format.html { redirect_to #camping, notice: 'Camping was successfully updated.' }
format.json { render :show, status: :ok, location: #camping }
else
format.html { render :edit }
format.json { render json: #camping.errors, status: :unprocessable_entity }
end
end
end
my edit.html.erb
<div class="containershow">
<h1>Editing Camping</h1>
<%= render 'form', camping: #camping %>
<%= link_to 'Show', #camping %> |
<%= link_to 'Back', campings_path %>
</div>
my new.html.erb
<h1>New Camping</h1>
<%= render 'form', camping: #camping %>
<%= link_to 'Back', campings_path %>
Edit solution ?
User can create and update his camping. I delete hidden_field
def create
# #camping = Camping.new(camping_params)
#camping = Camping.new((camping_params).merge(:user_id => current_user.id))
respond_to do |format|
if #camping.save
format.html { redirect_to #camping, notice: 'Camping was successfully created.' }
format.json { render :show, status: :created, location: #camping }
else
format.html { render :new }
format.json { render json: #camping.errors, status: :unprocessable_entity }
end
end
end
In Devise, the current user object is in current_user, available to your controllers. When saving the model, make sure to fill the user id field from that object, and not user input in the update action of your controller. Note that the edit action does not matter, that just renders the edit page, the actual update happens in update (if you follow the default conventions). Of course if you don't want users to even see other users' objects, you also need access control in other controller actions like edit as well, but that (implementing access control in a multi-tenant Rails application) is a different and much broader question.
More generally, be aware that anything that comes from a request can very easily be forged by a user. Always implement security server-side and do not trust user input!
Edit (seeing your code)
To prevent users updating others' Campings, you need to check in update after getting the #camping object (the second line) whether that's a camping object that your logged on user (current_user.id) is supposed to be able to edit.
The same way, if you want to prevent users from creating Campings for other users, you need to make sure in create that user_id will be set to the current user, something like #camping.user_id=current_user.id.
Similarly, if you want to prevent having a look at each other's Campings, you need to add checks to edit, show and pretty much all actions that return such objects.
There are gems like cancan and cancancan that may help with access control in Rails, they are worth a look!
Your Question is quite interesting but simple In the any HTML View Any one can change anything this will cause a security wise vulnerability as well.
To avoid these issues we need to authenticate it by two way You have to check the code by like It should be use by Controller not by view.
Suppose If you are creating any article of particular user
So To avoid it what you can do You can set the User ID in Session and make a Helper Method to find Current User always
So that you can find current user directly from controller and create article according to user
def Create
#article = current_user.articles.create(article_params)
end
This kind of Two way checking you can put up so that It will be safe.
To avoid the spend time on these work you can use gem directly like Devise

Retrieving form params in Rails 4 controller using fields_for and accepts_nested_attributes_for

I am positive this is the dumbest question but I cannot wrap my head around it.
I have two models in a simple has_one/belongs_to relationship
registration_code.rb
class RegistrationCode < ActiveRecord::Base
has_one :billing_transaction
accepts_nested_attributes_for :billing_transaction
billing_transaction.rb
class BillingTransaction < ActiveRecord::Base
belongs_to :registration_code
In my form I am collecting information for BOTH models using fields_for.
_form.html.erb (truncated example)
<%= form_for #registration_code, :html => {:class => "form", role: "form"} do |f| %>
<%= f.label :registration_code, "Registration Code", :class => "control-label" %>
<%= f.text_field :registration_code %>
<%= f.fields_for #billing_transaction do |bt| %>
<%= bt.label :transaction_amount, "Transaction Amount", :class => "control-label" %>
<%= bt.number_field :transaction_amount %>
<% end %>
<% end %>
In my controller, I have the following.
registration_code_controller.rb
def new
#registration_code = RegistrationCode.new
#billing_transaction = BillingTransaction.new
#billing_transaction.registration_code = #registration_code
end
def create
#registration_code = RegistrationCode.new(registration_code_params)
#billing_transaction = BillingTransaction.new # DOES THIS HAVE TO TAKE PARAMS?
#billing_transaction.registration_code = #registration_code # DO I NEED THIS LINE?
##### THE TROUBLE IS ON THIS NEXT LINE #####
#billing_transaction.transaction_amount = params[:billing_transaction_attributes][:transaction_amount] # THIS NEVER GETS SET! NOT SURE HOW TO ACCESS THE PARAMS
respond_to do |format|
if #registration_code.save && #billing_transaction.save
format.html { redirect_to registration_codes_path, notice: 'Registration code was successfully created.' }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def registration_code_params
params.require(:registration_code).permit(:registration_code, :expires_at, billing_transaction_attributes: [:transaction_amount])
end
The params are submitted and I can access the params for the primary model (registration_code) just fine. But I cannot for the life of me figure out how to get the parameters of the "sub" model (billing_transaction) and use them in the controller.
{"utf8"=>"✓",
"authenticity_token"=>"ePpqwJkeTAGMzb5WRWeI6aYCx4xpqvq4rl2m405IbwLdbp9xE0RyPgTZ6NmX8SvCFu94GKrfMfV9PrOkKa1BLg==",
"registration_code"=>{"registration_code"=>"HFmkbQEN",
"expires_at"=>"2015-07-16",
"billing_transaction"=>{"transaction_amount"=>"958.40" }},
"commit"=>"Create Registration Code"}
To access the billing_transaction.transaction_amount, for example, I have tried many variations:
params[:billing_transaction_attributes][:transaction_amount]
params[:billing_transaction][:transaction_amount]
params[#billing_transaction][:transaction_amount]
params[:registration_code][:billing_transaction][:transaction_amount]
No matter what I enter I cannot seem to access that nested array of parameters.
Help. Feeling super dumb right now. Thanks.
A few important changes to your new and create methods as below would solve your problem.
def new
#registration_code = RegistrationCode.new
#billing_transaction = #registration_code.build_billing_transaction
end
def create
#registration_code = RegistrationCode.new(registration_code_params)
respond_to do |format|
if #registration_code.save
format.html { redirect_to registration_codes_path, notice: 'Registration code was successfully created.' }
else
format.html { render :new }
format.json { render json: #customer.errors, status: :unprocessable_entity }
end
end
end
This is how the nested_attributes gets saved in the DB.
To retrieve the hash of billing transactions:
registration_code_params[:billing_transaction_attributes]
To retrieve the first (and only) key/value pair in the hash:
key, value = registration_code_params[:billing_transaction_attributes].first
puts key #transaction_amount
puts value #958.40

Rails Saving User Selected Foreign Key In Form

I am newbie to Rails and I have been struggling with this idea that just can't get over my head. For example I have
class Survey < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :survey
end
I have created a set of surveys. Now I want to create some questions and assign it to the survey through its foreign key survey_id. In the Question new.html.erb page, I used advanced form to show the Survey ID(I followed this tutorial). It works fine however, when I click submit, it seems like the survey_id doesn't save.
This is my question_controller.rb
def create
#question = Question.create(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
else
format.html { render :new }
end
end
def question_params
params.require(:question).permit(:description, :date_created, :survey_id)
end
Here is the form:
<%= form_for(#question) do |f| %>
<div class="field">
<%= f.label :survey_id %><br>
<%= collection_select(:question, :survey_id, Survey.all, :id, :description, prompt: true ) %>
</div>
<% end %>
I know in order for this to work, I have to do something like
#question = #survey.questions.create(...)
but I have no idea how to get the #survey instance before the user click on the drop down and select the appropriate survey.
Anyone has any idea on how to do this ??
Your create method should be
def create
#survey = Survey.find(params[:survey_id])
#question = #survey.questions.create(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
else
format.html { render :new }
end
end
or you can also use filter
class QuestionsController < ApplicationController
before_filter :set_survey, only: :create
def create
#question = #survey.questions.create(question_params)
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
else
format.html { render :new }
end
end
private
def set_survey
#survey = Survey.find(params[:survey_id]) || Survey.new
end
end
you have survey objects created and you want them to be associated to questions,
so, on your question's form if you are using select drop-down with survey names to select from then set select options values to survey id. so your question params will contain survey_id parameter with value equal to selected survey's id. and thus Question.create(question_params) will create question with survey_id.

undefined method `first_name' for nil:NilClass - No way this is Nil

User has many comments, comment belongs to many users. How do I fix this error?
undefined method `first_name' for nil:NilClass
when I try to do
<h3>Comments</h3>
<% #guide.comments.each do |comment| %>
<div>
<p><%= comment.user.first_name %></p>
</div>
<% end %>
user.rb
has_many :comments
comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
end
comments migration (I added a user_id column):
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :body
t.integer :user_id
t.timestamps
add_foreign_key :comments, :guides
end
end
end
comments controller:
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
long time ago but this could be usefull for someone with the same error.
you should delegate the first_name to the user and allow nil
class Comment < ActiveRecord::Base
belongs_to :user
delegate :first_name, to: :user, allow_nil: true, prefix: true
end
then call it in you view with
<h3>Comments</h3>
<% #guide.comments.each do |comment| %>
<div>
<p><%= comment.user_first_name %></p>
</div>
<% end %>
if there is no user, then it will be display nothing and not raise an exception
Ensure that you user model has a first_name attribute. Then confirm that your comment record (s) actually have a user associated with them. You may not have the user_id column whitelisted in the Comment class, so the user is not set
class Comment
attr_accessible :user_id, ...
end
Or in rails 4 you have strong parameters instead of attr_accessible
How is attr_accessible used in Rails 4?
I'm guessing that you did not set the user id while creating the comment object. can you try the following code?
def create
#comment = current_user.comments.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to #comment, notice: 'Comment was successfully created.' }
format.json { render action: 'show', status: :created, location: #comment }
else
format.html { render action: 'new' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
Model didn't find comment.user. It may be the comment's user_id havn't been set or the user_id didn't apper in "user" table "id" column. You can print the comment id and comment.user_id and check in DB.
Do you set:
has_many :comments, :dependent => :destroy
Or it could hapeen you delete the user but the user's comments remain, then for these comments, comment.user is null.
Are you sure your user_id is set when you create a comment ?
Maybe this simple line is missing in your controller
#comment.user = current_user
In order to be sure to have a user in your comment, you should add in your Comment model
validates_presence_of :user_id
and in your User model
has_many :comments, :dependent => :destroy
Defining methods in Ruby is very simple. To solve your problem, define
class << nil
def first_name; "John" end
def last_name; "Doe" end
end
And the error will disappear. All the nil objects are now named "John Doe".

understanding of rails object life cycle issue

I am new to rails.I have some confusion about about rails object life cycle.In rails we have the bellow code.
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
then in the form we have
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
my confusion is in the new action in controller i have #user = User.new
and again in the create #user = User.new(params[:user]).
then in form i have <%= form_for(#user) do |f| %> .
My question is here at the form the #user object actually means waht?
I mean does this #user is going to hit the new action or create action.
If it is going to hit the create action then how this is happening because the form is actually comes from the new action so i can't figure it out how its hitting to the create action .
i know its very simple question.But i dont know how its happening as i am new to rails.
Please help me to make me understand the object flow.
thanks in advance.
The "new" action makes a new object and shows a form for editing it. That form submits to the "create" action because the object has not been saved yet.
If you did
form_for #user
and #user was a previously-saved object, the form would submit to the update action instead.
form_for is a bit magical, like a lot of rails: it does two things:
sets the "action" attribute of the form to point at either "/users" (for create) and "/users/:id" (for update)
in the case of update (ie for objects that already have an id) it also adds a hidden field which triggers the update action: this hidden field will look like this: <input type="hidden" value="put" name="_method">.
Have a look at form_for in your rails api.
It's hitting create action because of the proper form URL. When you run rake routes command, you'll see that POST /users leads to users#create action - and that's the URL in the new form. URL is set (and form fields are generated) properly by Rails because you pass User instance to the form.

Resources