How to Use Current_User (Devise) with Nested Attributes (Cocoon)? - ruby-on-rails

name
metric
date_value
result_value
None of the above attributes are showing when I load the index page.
I know its because of this line: <% if averaged.user == current_user %>
More specifically it's because of the nested attributes of date_value and result_value (because if I take out those nested attributes the name & metric will show)
What do I need to add to the controller to allow the nested attributes to show on the index page, and in effect all the attributes?
I am using the cocoon gem and the devise gem.
Thanks in advance for your service!
<div id="values" class="panel panel-default">
<div class="panel-heading"><h4><b>AVERAGE</b></h4></div>
<!-- Table -->
<table>
<% #averaged_quantifieds.each do |averaged| %>
<% if averaged.user == current_user %>
<th class="value">
<%= link_to edit_quantified_path(averaged) do %>
<%= averaged.name %>
<% end %>
(<%= averaged.metric %>)
</th>
<tbody class="value">
<td><%= averaged.date_value.strftime("%m-%Y") %></td>
<td><%= averaged.result_value %></td>
</tbody>
<% end %>
<% end %>
</table>
</div>
controller
class QuantifiedsController < ApplicationController
before_action :set_quantified, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#averaged_quantifieds = current_user.quantifieds.averaged
#instance_quantifieds = current_user.quantifieds.instance
#averaged_quantifieds = Result.all.order("date_value")
#instance_quantifieds = Result.all.order("date_value")
end
def show
end
def new
#quantified = current_user.quantifieds.build
#quantified = Quantified.new
end
def edit
end
def create
#quantified = current_user.quantifieds.build(quantified_params)
if #quantified.save
redirect_to quantifieds_url, notice: 'Quantified was successfully created'
else
render action: 'new'
end
end
def update
if #quantified.update(quantified_params)
redirect_to quantifieds_url, notice: 'Goal was successfully updated'
else
render action: 'edit'
end
end
def destroy
#quantified.destroy
redirect_to quantifieds_url
end
private
def set_quantified
#quantified = Quantified.find(params[:id])
end
def correct_user
#quantified = current_user.quantifieds.find_by(id: params[:id])
redirect_to quantifieds_path, notice: "Not authorized to edit this goal" if #quantified.nil?
end
def quantified_params
params.require(:quantified).permit(:categories, :name, :metric, :result, :date, results_attributes: [:id, :result_value, :date_value, :_destroy])
end
end
quantified.rb
class Quantified < ActiveRecord::Base
belongs_to :user
scope :averaged, -> { where(categories: 'averaged') }
scope :instance, -> { where(categories: 'instance') }
has_many :results
accepts_nested_attributes_for :results, :reject_if => :all_blank, :allow_destroy => true
CATEGORIES = ['averaged', 'instance']
end
result.rb
class Result < ActiveRecord::Base
belongs_to :quantified
belongs_to :user
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
has_many :goals
has_many :values
has_many :quantifieds
has_many :results
end
Please let me know if you need any more code or comments to help bring this question to a resolution.

Related

rails, voting on nested comments

Ruby on Rails. Getting various errors while trying to add a voting feature via the acts_as_votable gem on nested comments.
The acts_as_votable works with the posts, but not with the nested comments under the posts.
With :
<%= link_to "Like", like_post_comment_path(#post, #comment), method: :put do %>
<i class="fa fa-arrow-up" aria-hidden="true">Yes</i>
<%= #p.get_upvotes.size %>
<% end %>
I get the error:
No route matches {:action=>"upvote", :controller=>"comments", :id=>nil, :post_id=>"1"}, missing required keys: [:id]
With:
<%= link_to "Like", like_post_comment_path(#post, #comment.id), method: :put do %>
<i class="fa fa-arrow-up" aria-hidden="true">Yes</i>
<%= #p.get_upvotes.size %>
<% end %>
I get the error:
undefined method `id' for nil:NilClass
I have tried various combinations as the parameters. All produce an error.
My Comments controller:
class CommentsController < ApplicationController
before_action :find_post, only: [:upvote, :downvote, :create, :destroy, :edit, :update]
before_action :find_comment, only: [:upvote, :downvote :destroy, :update, :edit, :comment_owner ]
before_action :comment_owner, only: [:destroy, :edit, :update]
def new
#comment = Comment.new
#post = Post.new
end
def create
#comment = #post.comments.create(params[:comment].permit(:content))
#comment.user_id = current_user.id
#comment.save
if #comment.save
redirect_back(fallback_location: root_path)
else
render 'new'
end
end
def destroy
#comment.destroy
redirect_back(fallback_location: root_path)
end
def edit
#comment = Comment.find(params[:id])
#p = Post.find(params[:post_id])
end
def update
if #comment.update(params[:comment].permit(:content))
respond_to do |f|
if (#comment.save)
f.html { redirect_to "/explore", notice: "Comment edited!" }
elsif
f.html { redirect_to "/explore", notice: "Error: Your Comment is the same!." }
else
render 'edit'
#f.html { render 'edit'} ## Specify the format in which you are rendering "new" page
end
end
end
end
def upvote
#comment.upvote_from current_user
redirect_back(fallback_location: root_path)
end
def downvote
#comment.downvote_from current_user
redirect_back(fallback_location: root_path)
end
private
def find_post
#post = Post.find(params[:post_id])
end
def find_comment
#comment = #post.comments.find(params[:id])
end
def comment_owner
unless current_user.id == #comment.user_id
flash[:notice] = "You can't do that!"
redirect_back(fallback_location: root_path)
end
end
end
Comment model:
class Comment < ApplicationRecord
belongs_to :commentable, :polymorphic => true
belongs_to :user
acts_as_votable
# scope :desc
default_scope { order(created_at: :desc) }
end
Post model:
class Post < ApplicationRecord
belongs_to :user
has_many :comments, :as => :commentable
attr_accessor :post_id
acts_as_votable
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 100} # Questions are capped at 100 chars.
default_scope { order(cached_votes_score: :DESC) }
end
User model:
class User < ApplicationRecord
has_many :posts
has_many :comments, :as => :commentable
acts_as_voter
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts, dependent: :destroy
def user
user = User.find_by(params[:id])
end
Routes:
like_post_comment PUT /posts/:post_id/comments/:id/like(.:format) comments#upvote
dislike_post_comment PUT /posts/:post_id/comments/:id/dislike(.:format) comments#downvote

Avatar is not showing for users

I am using devise as my user authentication and carrierwave gem for image uploading. Now everything works well and the avatar gets saved in the users table and is shown inside the index view; but not inside the show view.
To make my question a bit more clear:
Inside the index view, the avatar get's successfully shown.
Inside the show view, the avatar falls to the default image because #user.avatar is blank/nil
Show code:
<div class="well">
<div class="media">
<a class="pull-left">
<% if #user.avatar.blank? %>
<img src="http://www.adtechnology.co.uk/images/UGM-default-user.png" style="width: 75px;">
<% elsif #user.avatar %>
<%= image_tag #user.avatar, :style => "width:75px;" %>
<% end %>
</a>
<div class="media-body">
<p>About <%= link_to #question.user.username, #question.user, :class => " bg" %></p>
</div>
<p class="text-muted small">Apparently this user doesn't like to share his information.</p>
</div>
</div>
Question controller:
class QuestionsController < ApplicationController
before_action :set_question, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#questions = Question.all
respond_with(#questions)
end
def show
#user = User.find(params[:id])
respond_with(#question)
end
def new
if user_signed_in?
#question = current_user.questions.build
respond_with(#question)
else
redirect_to new_user_session_path
end
end
def edit
end
def create
#question = current_user.questions.build(question_params)
#question.save
respond_with(#question)
end
def update
#question.update(question_params)
respond_with(#question)
end
def destroy
#question.destroy
respond_with(#question)
end
private
def set_question
#question = Question.find(params[:id])
end
def question_params
params.require(:question).permit(:title, :description)
end
end
User model:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
has_many :questions, :dependent => :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
Question model:
class Question < ActiveRecord::Base
belongs_to :user
end
I fixed it by changing these lines inside the show.html.erb :
<% if #question.user.avatar.blank? %>
<img src="http://www.adtechnology.co.uk/images/UGM-default-user.png" style="width: 75px;">
<% elsif #question.user.avatar %>
<%= image_tag #question.user.avatar, :style => "width:75px;" %>
<% end %>
def show
#user = User.find(params[:id])
respond_with(#question)
end
Since the show action's called in QuestionsController, params[:id] will be #question's id. You should use #question.user to refer to the author of #question:
def show
#user = #question.user
respond_with(#question)
end

#comments nil while #event.comments works in show partial

I cannot figure out why #comments is returning nil when I am attempting to loop through it. If I use #event.comments.each do instead it works just fine. My current structure is User / Events / Comments.
Comments Controller:
class CommentsController < ApplicationController
before_action :authenticate_user!, only: [:create, :destroy]
def create
#event = Event.find(params[:event_id])
#comment = #event.comments.create(comment_params)
#comment.user = current_user
if #comment.save
flash[:notice] = "Comment Added"
redirect_to #event
else
flash[:alert] = "Comment Not Added"
redirect_to #event
end
end
def show
#event = Event.find(params[:id])
#comments = #event.comments
end
def destroy
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
Events Controller Show Action:
class EventsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create,:edit, :update, :show,
:index, :destroy]
def show
#event = Event.find(params[:id])
end
private
def event_params
params.require(:event).permit(:start_date, :start_time, :location, :title, :description, :size, :difficulty,
:activity, :duration)
end
end
Comment Model:
class Comment < ActiveRecord::Base
belongs_to :event
belongs_to :user
validates :body, presence: true
scope :newest, -> { order("created_at DESC") }
end
User Model:
class User < ActiveRecord::Base
has_many :created_events, class_name: 'Event', :foreign_key => "creator_id",
dependent: :destroy
has_many :registers, :foreign_key => "attendee_id", dependent: :destroy
has_many :attended_events, through: :registers, dependent: :destroy
has_many :comments, through: :events
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable
validates :name, presence: true, uniqueness: true, length: { maximum: 50 }
validates :email, presence: true, uniqueness: { case_sensitive: true }
validate :validate_name
def validate_name
if User.where(email: name).exists?
errors.add(:name, :invalid)
end
end
end
Event Model:
class Event < ActiveRecord::Base
scope :latest, -> { order(date: :asc, time: :asc)}
belongs_to :creator, class_name: 'User'
has_many :registers, :foreign_key => 'attended_event_id', dependent: :destroy
has_many :attendees, through: :registers, dependent: :destroy
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { maximum: 50 }
validates :description, presence: true, length: { maximum: 500 }
validates :location, presence: true
validates :start_time, presence: true
validates :start_date, presence: true
validates :activity, presence: true
validates :difficulty, presence: true
end
and lastly, the comments/_show.html.erb partial:
<% if #comments %>
<span class="results-number color-aqua-show">Comments</span>
<% #comments.each do |comment| %>
<p class="comments">
<i class="color-green fa fa-user ride-i"></i>
<%= comment.user.name %>: <%= time_ago_in_words(comment.created_at).capitalize %> ago
</p>
<p>
<i class="color-aqua fa fa-comment ride-i"></i>
<%= comment.body %>
</p>
<div class="bottom-breaker"></div>
<% end %>
<% else %>
<span class="results-number color-aqua-show">Be the first to comment!</span>
<% end %>
Show form from events:
<div class="container s-results margin-bottom-50">
<div class="row">
<div class="col-md-9">
<%= render partial: 'comments/show' %>
<%= render partial: 'comments/form' %>
</div>
</div>
</div>
Again, if I change #comments in the partial to #events.comments it will recognize that there are comments for the particular event and loop through them. This has been driving me insane for the better part of 5 hours now. Thanks.
As Pardeep Saini said, you need to add #comments to events#show:
def show
#event = Event.find params[:id]
#comments = #event.comments
end
The problem is that #comments is a variable, which needs to be defined. If it isn't defined, then you're going to receive the equivalent of an undefined error.
Thus, to fix it, you need to make sure that you're calling a defined variable; either #comments (if you've defined it), or #event.comments.
I think there is a much deeper issue with your structure (from looking at your code).
You'd be better setting it up like this:
#config/routes.rb
resources :events do
resources :comments, only: [:create, :destroy] #-> url.com/events/:event_id/comments...
end
#app/controllers/comments_controller.rb
class EventsController < ApplicationController
def show
#event = Event.find params[:id]
#comments = #event.comments
end
end
This will allow you to use the following:
#app/views/events/show.html.erb
<%= #event.title %>
<%= render #comments %>
<%= render "new_comment" %>
#app/views/events/_comment.html.erb
<%= comment.user.name %>: <%= time_ago_in_words(comment.created_at).capitalize %> ago
<%= comment.body %>
#app/views/events/_new_comment.html.erb
<%= form_for #event.comments.build do |f| %>
<%= f.text_field :body %>
<%= f.submit %>
<% end %>
This will make it so that if you browse to url.com/events/1, it will output all the event's comments.
The added benefit of this setup is the ability to create / destroy comments:
#app/controllers/comments_controller.rb
class CommentsController < ApplicationController
before_action :set_event
def create
#comment = #event.comments.new comment_params
#comment.user = current_user
#comment.save
end
def destroy
#comment = #event.comments.find params[:id]
#comment.destroy
end
private
def comment_params
params.require(:comment).permit(:body, :user)
end
def set_event
#event = Event.find params[:event_id]
end
end
Solved the problem. It was a very dumb error where I had show listed twice in my events controller. The bottom one was over riding the top.

Rails - nested model input data not appearing in "show" page

I am having trouble figuring out how to make some data collected through a nested model appear on the "show" page. I have a rails app with 3 models, a User model, a Project model, and a Team model. The model associations are as follows:
Project:-
class Project < ActiveRecord::Base
has_many :users, :through => :team
has_one :team, :dependent => :destroy
accepts_nested_attributes_for :team, allow_destroy: true
end
Team:-
class Team < ActiveRecord::Base
belongs_to :project
has_many :users
end
User:-
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_and_belongs_to_many :teams
end
Every project has one team, and every team consists of many users who are already saved in the database. What I would like to do exactly is to make it possible to select multiple existing users within the project form (through a nested form) and save them to a model called team. I managed to get the form working correctly, but im not sure how to go about saving the data collected to the team model, and then to make the group of users that were selected (the team) to appear in project's show page. Please help!
P.S I used the nested form gem to add multiple team members within the project's form.
Projects Show page:-
<%= bootstrap_nested_form_for(#project, :html => {:multipart => true}, layout: :horizontal) do |f| %>
<% f.fields_for :teams do |builder| %>
<% if builder.object.new_record? %>
<%= builder.collection_select :user, User.all, :id, :email, { prompt: "Please select", :selected => params[:user], label: "Employee" } %>
<% else %>
<%= builder.hidden_field :_destroy %>
<%= builder.link_to_remove "Remove" %>
<% end %>
<%= f.link_to_add "Add Team Member", :teams %>
<%= f.submit %>
<% end %>
projects controller:-
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#projects = Project.all
respond_with(#projects)
end
def show
respond_with(#project)
end
def new
#project = Project.new
#project.pictures.build
#project.teams.build
respond_with(#project)
end
def edit
#project = Project.find(params[:id])
#project.pictures.build
#project.teams.build
end
def create
#project = Project.new(project_params)
if #project.save
flash[:notice] = "Successfully created project."
redirect_to #project
else
render :action => 'new'
end
end
def update
#project.update(project_params)
respond_with(#project)
end
def destroy
#project.destroy
respond_with(#project)
end
private
def set_project
#project = Project.find(params[:id])
end
def project_params
params.require(:project).permit(:id, :title, :description, :status, :phase, :location, :image, pictures_attributes: [:id, :image], teams_attributes: [:project_id, :user_id])
end
end

"Undefined local variable or method" error when using commontator gem for comments

I made a website in which people can share photo's (they are called pins in my code). I wanted to add a system in which, when someone clicks on the picture, they can comment on it. I decided to use the commontator gem and I installed it. My problem is that the commenting system does not show up below posts like it's supposed to and I get an undefined local variable or method error for my pins controller.
routes.rb
Photo::Application.routes.draw do
resources :pins
devise_for :users
root "pins#index"
get "about" => "pages#about"
mount Commontator::Engine => '/commontator'
show.html.erb
<%= link_to 'Back', pins_path %>
<div class="row">
<div class="col-md-offset-2 col-md-8">
<div class="panel panel-default">
<div class="panel-heading center">
<%= image_tag #pin.image.url(:medium) %>
</div>
<div class="panel-body">
<p><%= #pin.description %></p>
<p><strong><%= #pin.user.name if #pin.user %></strong></p>
<%= commontator_thread(commontable) %>
<% if #pin.user == current_user %>
<%= link_to edit_pin_path(#pin) do %>
<span class="glyphicon glyphicon-edit"></span>
<% end %>
<% end %>
</div>
</div>
</div>
pin.rb
class Pin < ActiveRecord::Base
belongs_to :user
acts_as_commentable
has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
validates :image, presence: true
acts_as_commontator
acts_as_commontable
end
pins_controller.rb
class PinsController < ApplicationController
before_action :set_pin, only: [:show, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
def index
#pins = Pin.all.order("created_at DESC").paginate(:page => params[:page], :per_page => 8)
end
def show
end
def new
#pin = current_user.pins.build
end
def edit
end
def create
#pin = current_user.pins.build(pin_params)
if #pin.save
redirect_to #pin, notice: 'Pin was successfully created.'
else
render action: 'new'
end
end
def update
if #pin.update(pin_params)
redirect_to #pin, notice: 'Pin was successfully updated.'
else
render action: 'edit'
end
end
def destroy
#pin.destroy
redirect_to pins_url
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
def correct_user
#pin = current_user.pins.find_by(id: params[:id])
redirect_to pins_path, notice: "Not authorized to edit this pin" if #pin.nil?
end
def pin_params
params.require(:pin).permit(:description, :image)
end
end
User model 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 :pins, dependent: :destroy
validates :name, presence: true
acts_as_commontator
end
error I am getting on show.html.erb
NameError in Pins#show
undefined local variable or method `commontable' for #<#<Class:0x007f9d8ccec328>:0x007f9d8df68768>
Extracted source (around line #12):
<div class="panel-body">
<p><%= #pin.description %></p>
<p><strong><%= #pin.user.name if #pin.user %></strong></p>
**<%= commontator_thread(commontable) %>**
<% if #pin.user == current_user %>
<%= link_to edit_pin_path(#pin) do %>
As there is no stacktrace added, a couple of observations.
acts_as_commontator and acts_as_commontable are added in same model.
As per documentation at https://github.com/lml/commontator
acts_as_commontator // to be added in user model(s) (or any models that should be able to post comments)
acts_as_commontable // to be added in models you want to be able to comment on
So can you try moving acts_as_commontator to user model?
In pin.rb line no. 3,.remove the line acts_as_commentable which is not used by your gem commontator
Assuming that you have added acts_as_commontable to the Pin model,
In the pins/show.html.erb,
Replace
<%= commontator_thread(commontable) %>
With
<%= commontator_thread(#pin) %>
As per the Commontator Usage Documentation,
In <%= commontator_thread(commontable) %>
commontable is an instance of a model that acts_as_commontable.
which in your case is #pin.

Resources