Rails 4, Devise associate users to post - ruby-on-rails

I have Devise setup and can create posts, but I would like to add the username of the creator of the post.
Am I missing something?
posts controller:
def create
#post = current_member.posts.new(params[:post])
#post = Post.new(post_params)
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render action: 'show', status: :created, location: #post }
else
format.html { render action: 'new' }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
post model:
class Post < ActiveRecord::Base
belongs_to :member
end
member model: (I'm using member as user)
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts
end
In show.html I don't know what to put on the buttom to display the username. I get errors or it will just display the current user email on all post until i log out, then nil error of course.
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= #post.title %>
</p>
<p>
<strong>Author:</strong>
<%= #post.author %>
</p>
<p>
<strong>Main:</strong>
<%= #post.main %>
</p>
<%= current_member.email %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<%= link_to 'Back', posts_path %>

I presume you don't want the logged-in member/user's e-mail with the post but instead the author's e-mail. Try: #post.member.email

Related

Rails 6.1.3.2 Unpermitted parameter and User must exist

Few years ago I develop aps in Rails 4 and now many things change.
I user Shire GEM in this example to upload photos:
Ok, my models:
Photo model:
class Photo < ApplicationRecord
include ImageUploader::Attachment(:image)
belongs_to :user
end
User model ( i put only few lines):
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_one :profile, :dependent => :destroy
has_many :photos, :dependent => :destroy
end
PhotosController:
class PhotosController < ApplicationController
before_action :set_photo, only: %i[ show edit update destroy ]
before_action :authenticate_user!
def create
#photo = Photo.new(photo_params)
respond_to do |format|
if #photo.save
format.html { redirect_to #photo, notice: "Photo was successfully created." }
format.json { render :show, status: :created, location: #photo }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_photo
#photo = Photo.find(params[:id])
end
# Only allow a list of trusted parameters through.
def photo_params
params.require(:photo).permit(:title, :image_data, :image, :user_id)
end
end
UsersController:
class UsersController < ApplicationController
private
# Only allow a list of trusted parameters through.
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:id)
end
end
And now last thing, form for add photos in view:
<%= form_with(model: photo) do |form| %>
<% if photo.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(photo.errors.count, "error") %> prohibited this photo from being saved:</h2>
<ul>
<% photo.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="field">
<%= form.label :image %>
<%= form.file_field :image %>
</div>
<%= current_user.id %> // SHOWS USER ID
//// THIS GENERATE ERROR ////
<%#= form.hidden_field :user_id => current_user.id %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
And where I have problem. When I to it in that way I see in logs unpermited parameters :user_id.
But when I submit form I see error "User must exist".
I found solution and change in PhotosController this line:
def create
#photo = Photo.new(photo_params)
to:
def create
#photo = current_user.photos.new(photo_params)
and it start working. Photo have user_id in table. But I want to know why I can't add user_id for photos in form in view like:
<%= form.hidden_field :user_id => current_user.id %>
Never pass the user id as plaintext through the parameters. Get it from the session instead. Its trivial for any malicous user to use the web inspector and simply fill in the hidden input and then upload a unseemly picture as ANY user.
The session cookie is encrypted and much more difficult to tamper with.
class PhotosController < ApplicationController
before_action :authenticate_user!
def create
# build the record off the current_user
#photo = current_user.photos.new(photo_params)
respond_to do |format|
if #photo.save
format.html { redirect_to #photo, notice: "Photo was successfully created." }
format.json { render :show, status: :created, location: #photo }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
private
# Only allow a list of trusted parameters through.
def photo_params
params.require(:photo).permit(:title, :image_data, :image)
end
end
But I want to know why I can't add user_id for photos in form in view like:
<%= form.hidden_field :user_id => current_user.id %>
Because you're calling the method with the wrong arguments. The signature is hidden_field(object_name, method, options = {}) but as already stated its a bad idea.

Rails 4 - how to get user name from their id

I have a order show page shown below. I had this working but ever since I changed computers to work on this app, the name did not display.
If I change <%= #order.user.name %> to <%= #order.user.id %>, I get the correct id. Otherwise I get nothing displaying where as the name of the id should be posted.
#view/orders/show.html.erb
<p>
<strong>Code:</strong>
<%= #order.code %>
</p>
<p>
<strong>Client:</strong>
<%= #order.client.name %>
</p>
<p>
<strong>User:</strong>
<%= #order.user.name %>
</p>
<p>
<strong>Notes:</strong>
<%= #order.memo %>
</p>
<p>
<strong>Status:</strong>
<%= #order.status ? "Confirmed" : "In Progress" %>
</p>
<%= link_to 'Edit', edit_order_path(#order) %> |
<%= link_to 'Back', orders_path %>
#models/order.rb snippet
class Order < ActiveRecord::Base
belongs_to :user
end
#model/user.rb
class User < ActiveRecord::Base
has_many :orders, dependent: :destroy
has_many :addresses, dependent: :destroy
has_many :telephones, dependent: :destroy
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
enum role: [:user, :manager, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :user
end
end
#controllers/order_controller.rb snippet
def create
#order = Order.new(order_params)
#order.user_id = current_user.id
#order.status = TRUE
respond_to do |format|
if #order.save
format.html { redirect_to #order, notice: 'Order was successfully created.' }
format.json { render :show, status: :created, location: #order }
else
format.html { render :new }
format.json { render json: #order.errors, status: :unprocessable_entity }
end
end
end
I think I just answered another question of yours, but I would recommend using the .delegate method like this:
#app/models/order.rb
Class Order < ActiveRecord::Base
belongs_to :user
delegate :name, to: :user, prefix: true #-> #order.user_name
end
You can delegate multiple variables if you need to.
This fixes Law of Dementer, as described here
As mentioned in comments, the value for the user name is empty and that is why it displays a blank when looking for the name.
Adding a name(string) to the user.name will solve the issue
When using a different database, make sure to also update the database with data, preferably the same data which initially tested with.
It's completely independent of the machine you use, so there have to be some changes you've made in your code that you don't remember.
Check what value is returned when you call this user from the console. Type rails c in the terminal and then type a command:
User.find(<<ID_OF_USER_WHOES_NAME_IS_NOT_DISPLAYED>>).name
If its name is empty, it could be a problem with creating a user or something.
Make update when you'll check it.

Comment functionality in Rails. undefined method `first_name' for nil:NilClass

One thing I could never do properly is implement a comment feature. I'm not leaving my computer until I learn to do it.
The error is thrown on this line:
<strong><%= comment.user.first_name %></strong>
Apparently user is nil; but why? And what do I have to do to get this to work?
A comment should belong to a guide and a user. Users and guides both have many comments.
I started with
rails g scaffold comment body:text guide:references user:references
and then migrated the database. I completed the model associations as well.
Here is my guides controller show action:
def show
#guide = Guide.find(params[:id])
#comment = #guide.comments.build
end
Here is the part of the Guide show view that deals with comments:
<h3>Comments</h3>
<% #guide.comments.each do |comment| %>
<div>
<strong><%= comment.user.first_name %></strong>
<br />
<p><%= comment.body %></p>
</div>
<% end %>
<%= render 'comments/form' %>
Here is the comment form partial:
<%= simple_form_for(#comment) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :body %>
<%= f.association :user %>
<%= f.association :guide %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, #:recoverable,
:rememberable, :trackable, :validatable
validates :first_name, presence: true
validates :email, presence: true
validates :email, uniqueness: true
validates :runescape_username, presence: true
has_many :guides
has_many :comments
acts_as_voter
def user_score
self.guides.inject(0) { |sum, guide| sum += guide.score }
end
end
Comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :guide
end
Comments controller create action:
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
Replace the line
#comment = Comment.new(comment_params)
with
#comment = current_user.comments.build(comment_params)
in your Comments#create action.
You get this error because you don't assign current_user to created Comment. That's why comment.user returns nil.
As stated by AndreDurao, you can also validate user_id presence in Comment model, like this:
class Comment
validates_presence_of :user
# ...
end
for getting rid of that error try this <%= comment.user.try(:first_name) %>

How to allow users to comment

So, I'd like users to be able to comment. At the present moment anyone can comment just by typing in a arbitrary name in the name field.
But I'd like to associate a comment with a user. So there will no longer be a need for a name field in the comments form as it will be the users name.
How can this be done?
I've followed Ryan Bates railscast but he never associates comments with users.
comments_controller.rb
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
def index
#comments = Comment.where("song_id IS NOT ?", nil)
end
def show
end
# GET /comments/new
def new
end
# GET /comments/1/edit
def edit
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
respond_to do |format|
if #comment.save
format.html { redirect_to song_url(#comment.song_id), 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
# PATCH/PUT /comments/1
# PATCH/PUT /comments/1.json
def update
respond_to do |format|
if #comment.update(comment_params)
format.html { redirect_to song_url(#comment.song_id), notice: 'Comment was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #comment.errors, status: :unprocessable_entity }
end
end
end
# DELETE /comments/1
# DELETE /comments/1.json
def destroy
#comment.destroy
redirect_to song_url(#comment.song_id)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:song_id, :author_name, :site_url, :content, :user_id)
end
end
user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :songs
has_many :comments
acts_as_voter
end
comment.rb
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :song
end
comments#form.html.erb
<%= form_for #comment do |f| %>
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div id="comment_form">
<div class="field">
<%= f.hidden_field :song_id %>
<p>
<%= f.text_field :author_name, placeholder: "Name" %>
</p>
<p>
<%= f.text_area :content, :rows => '12', :cols => 35, placeholder: "Leave a comment..." %>
</p>
<p><%= f.submit "Submit" %></p>
<% end %>
<br /><br />
</div></div>
Your Comment table should have a column named user_id if it does not already. Then you can assign the user_id two different ways. These assume you have a current_user method. If you do not, then you will have to fill in the user_id from whatever session store or method you are using.
You could create a hidden_field in your form to assign it.
<%= f.hidden_field :user_id, value: current_user.id %>
but as noted by #rmagnum2002 this could be a security concern due to a user could edit this.
You could assign it during the create action:
def create
#comment = Comment.new(comment_params)
#comment.user_id = current_user.id
respond_to do |format|
if #comment.save
format.html { redirect_to song_url(#comment.song_id), 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
Assigning this in the controller create action is probably best.

Rails - ArgumentError in UsersController#create - too few arguments

This is probably really basic but I can't seem to figure it out.
Essentially, when I try to create a new user using a form, and the user details are already present and not unique, I receive he following error:
ArgumentError in UsersController#create
too few arguments
Application Trace | Framework Trace | Full Trace
app/controllers/users_controller.rb:61:in `format'
app/controllers/users_controller.rb:61:in `create'
Here's my create action in my user_controller.rb:
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
if #user.save
flash[:notice] = 'User successfully created' and redirect_to :action=>"index"
else
format.html { render :action => "new" }
format.xml { render :xml => #user.errors, :status => :unprocessable_entity }
end
end
end
And here's my user.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :username, :password, :password_confirmation, :remember_me
validates :email, :username, :presence => true, :uniqueness => true
end
Here's also my form:
<%= simple_form_for(#user) do |f| %>
<div class="field">
<%= f.input :username %>
</div>
<div class="field">
<%= f.input :email %>
</div>
<div class="field">
<%= f.input :password %>
</div>
<div class="field">
<%= f.input :password_confirmation %>
</div>
<div class="actions">
<%= f.button :submit %>
</div>
<% end %>
What's format in this case?
There's no respond_to block, put it back in! You're referencing some other format.
The exact layout of the code has changed a bit through different rails version (please post what version you are using - check the Gemfile).
This example is for rails 3+ (it was generated using 3.2.5 but should apply to all 3+ or at least 3.1+ versions)
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'Blob 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
p.s. Good choice with simple_form, it makes life MUCH easier!

Resources