undefined method `destroy' on Public Activity - ruby-on-rails

User's can comment on a Screen and it's tracked by PublicActivity :
#comment.create_activity :create, owner: current_user, recipient: #comment.screen.user
and the comments are dependent: :destroy on the screen model.
But when i delete a screen, while the comments are deleted, the Record from PublicActivity for that comment still exists.
here's my Screens Controller:
def destroy
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy #<-- Heres the Problem
#screen.destroy
respond_to do |format|
format.html { redirect_to root_path }
format.json { head :no_content }
end
end
But upon deleting a Screen, i'm getting undefined methoddestroy' for nil:NilClass`.
I read on Railscast:
it was due to calling the create_activity method after the object had
been destroyed.
According to the gem maintainers, you simply have to assume the record
will be destroyed, and call create_activity before the destroy
What am i missing?
Informations below
screen.rb
belongs_to :user
has_many :comments, :dependent => :destroy
comment.rb
belongs_to :user
belongs_to :screen
screens_contoller.rb
def create
#screen = current_user.screens.build(screen_params)
respond_to do |format|
if #screen.save
format.html { redirect_to #screen, notice: 'You successfully uploaded your Screenshot.' }
format.json { render action: 'show', status: :created, location: #screen }
current_user.add_points(2, 'Points for Uploading a Screenshot')
else
format.html { render action: 'new' }
format.json { render json: #screen.errors, status: :unprocessable_entity }
end
end
end
def destroy
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy
#screen.destroy
respond_to do |format|
format.html { redirect_to root_path }
format.json { head :no_content }
current_user.substract_points(1, "Substraction for Deleting a Screenshot")
end
end
comments_controller.rb
def create
#screen = Screen.find(params[:screen_id])
#comment = current_user.comments.build(comment_params)
#comment.screen_id = #screen.id
respond_to do |format|
if #comment.save
# Create Record for Public Activity
#comment.create_activity :create, owner: current_user, recipient: #comment.screen.user
format.html { redirect_to #screen, 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
def destroy
#comment.destroy
respond_to do |format|
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy
format.html { redirect_to :back }
format.json { head :no_content }
end
end
That's how my Screen Controller Destroy Action looks like right now:
def destroy
#screen = current_user.screens.find(params[:id])
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy
#screen.destroy
current_user.substract_points(1, "Substraction for Deleting a Screenshot")
respond_to do |format|
format.html { redirect_to root_path }
end
end
Again the same error:

This isn't tested, but this is what I think you should do.
First you can remove the references to activities in your screens_controller#destroy
Then in your comments_controller#destroy
#comment = current_user.comments.find(params[:id])
#activity = PublicActivity::Activity.find_by(trackable_id: (params[:id]), trackable_type: controller_path.classify)
#activity.destroy
#comment.destroy
Should be outside of your respond to block
Next in your comments model you should do something like this:
#comment.rb
private
before_destroy :find_and_destroy_comments
def find_and_destroy_comments
activity = PublicActivity::Activity.find_by(trackable_id: self.id, trackable_type: self.class.name)
if activity.present?
activity.destroy
end
end
calling the before_destroy method overrides the default ruby destroy method that is called during dependent: :destroy
Let me know if this works, but It should.

Related

Merit doesn't add points to user after create action

I've used this instructions for simply add score when a user creates a "solucion" (which is a kind of "answer" to a micropost). I have added the has_merit line to user.rb (user model).
I want to display the user points earned for that action at the show view.
show.html.erb (for solucion):
<h2><span class="red"><%= current_user.points %></span><br>Points</br></h2>
It displays 0 points...
point_rules.rb:
module Merit
class PointRules
include Merit::PointRulesMethods
def initialize
score 5, on: 'solucions#create'
end
end
end
When I create a solucion with the current_user (already saving the user_id index and identifier to solucion), This is what my rails server output shows...
Direct link to github gist:
https://gist.github.com/roadev/7b34fd67ab93c979fa48
Embed:
<script src="https://gist.github.com/roadev/7b34fd67ab93c979fa48.js"></script>
EDIT:
solucions_micropost.rb
class SolucionsController < ApplicationController
before_action :set_solucion, only: [:show, :edit, :update, :destroy]
def index
#solucions = Solucion.all
end
def show
end
def new
#solucion = current_user.solucions.build
end
def edit
end
def create
#solucion = current_user.solucions.build(solucion_params)
respond_to do |format|
if #solucion.save
format.html { redirect_to #solucion, notice: 'Solucion was successfully created.' }
format.json { render action: 'show', status: :created, location: #solucion }
else
format.html { render action: 'new' }
format.json { render json: #solucion.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #solucion.update(solucion_params)
format.html { redirect_to #solucion, notice: 'Solucion was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #solucion.errors, status: :unprocessable_entity }
end
end
end
def destroy
#solucion.destroy
respond_to do |format|
format.html { redirect_to solucions_url }
format.json { head :no_content }
end
end
private
def set_solucion
#solucion = Solucion.find(params[:id])
end
def current_micropost
#solucion = microposts.find_by(id: params[:id])
end
def solucion_params
params.require(:solucion).permit(:solucion, :image, :micropost_id)
end
end
user.rb:
class User < ActiveRecord::Base
has_many :dreams
has_many :microposts
has_many :solucions
has_merit
end
I had a problem with a migration when I installed the merit gem.

how do I write create method in the controller for a submission form that uses a join table?

I'm trying to create a form that allow called submits. I've got all the appropriate MVC created. I've then created a model called questions that works and am using active admin to allow admin users to add new questions to the form as they see fit. When I test submitting the form I get this error
undefined method `each' for nil:NilClass
#submit = Submit.new(submit_params)
#submit.save
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
Here's my submits controller:
class SubmitsController < ApplicationController
before_action :set_submit, only: [:show, :edit, :update, :destroy]
def index
#submits = Submit.all
end
def show
end
def new
#submit = Submit.new
#questions = Question.all
end
def edit
end
def create
#submit = Submit.new(submit_params)
#submit.save
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
respond_to do |format|
if #submit.save
format.html { redirect_to #submit, notice: 'Application was successfully created.' }
format.json { render :show, status: :created, location: #submit }
else
format.html { render :new }
format.json { render json: #submit.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #submit.update(submit_params)
format.html { redirect_to #submit, notice: 'Application was successfully updated.' }
format.json { render :show, status: :ok, location: #submit }
else
format.html { render :edit }
format.json { render json: #submit.errors, status: :unprocessable_entity }
end
end
end
def destroy
#submit.destroy
respond_to do |format|
format.html { redirect_to submits_url, notice: 'Submit was successfully destroyed.' }
format.json { head :no_content }
end
end
Here's my Submit and Question model:
Submit:
class Submit < ActiveRecord::Base
has_and_belongs_to_many :questions
belongs_to :user
end
Question:
class Question < ActiveRecord::Base
has_and_belongs_to_many :submits
end
I'm sure it's some kind of syntax error in my controller but I don't know what. Still pretty new to using join tables. Any help/explanation would be very appreciated.
Thanks!
You don't need this
params[:submit][:question_ids].each do |question_id|
#question = Question.find(question_id)
#submit.questions << #question
end
I don't see your submit params but if you add question ids to the permitted parameters then rails will build the entry in the join table on it's own.
def submit_params
params.require(:submit).permit(:user_id, question_ids: [])
end

ActiveModel::ForbiddenAttributesError Rails 4.1

I'm getting the following ActiveModel::ForbiddenAttributesError when creating a comment on my app.
The error message precise that the problem comes from line 7 in my Comments Controller file: #comment = #pin.comments.create(params[:comment])
app/controllers/comments_controller.rb
class CommentsController < ApplicationController
before_filter :authenticate_user!
def create
#pin = Pin.find(params[:pin_id])
#comment = #pin.comments.create(params[:comment])
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
private
def comment_params
params.require(:comment).permit(:body, :pin_id)
end
end
here is the comment model
class Comment < ActiveRecord::Base
belongs_to :pin
end
Any help with this error message?
You should replace this line with
#comment = #pin.comments.create(comment_params)
Also, putting pin_id in permitted parameters is unnecessary (since you create comment through #pin.comments association) and possibly unsafe (user could associate comment with other Pin).

How do I access an associated model of an associated model?

I have a Topic which has_many Posts. Each Post belongs to a User, and each User has_one Profile.
In my "show" page for a specific Topic, I try to display profile information of the user who created the post:
<% #topic.posts.each do |post| %>
<%= post.user.profile.first_name %>
<% end %>
I get the following error:
undefined method `profile' for nil:NilClass
Any idea why it does not allow me to access the profile? Please advise.
My Topic controller is as follows:
class TopicsController < ApplicationController
# GET /topics
# GET /topics.json
add_breadcrumb :index, :topics_path
def index
if params[:tag]
#topics = Topic.tagged_with(params[:tag])
else
#topics = Topic.all
end
#newtopic = Topic.new
respond_to do |format|
format.html # index.html.erb
format.json { render json: #topics }
end
end
# GET /topics/1
# GET /topics/1.json
def show
#topic = Topic.find(params[:id])
#posts = #topic.posts
#newpost = #topic.posts.build
add_breadcrumb #topic.name
respond_to do |format|
format.html # show.html.erb
format.json { render json: #topic }
end
end
# GET /topics/new
# GET /topics/new.json
def new
add_breadcrumb :new, :topics_path
#topic = Topic.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #topic }
end
end
# GET /topics/1/edit
def edit
#topic = Topic.find(params[:id])
end
# POST /topics
# POST /topics.json
def create
#topic = Topic.new(params[:topic])
#topic.user_id = current_user.id
#topic.last_poster_id = current_user.id
#topic.last_post_at = Time.now
respond_to do |format|
if #topic.save
format.html { redirect_to #topic, notice: 'Topic was successfully created.' }
format.json { render json: #topic, status: :created, location: #topic }
else
format.html { render action: "new" }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# PUT /topics/1
# PUT /topics/1.json
def update
#topic = Topic.find(params[:id])
respond_to do |format|
if #topic.update_attributes(params[:topic])
format.html { redirect_to #topic, notice: 'Topic was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE /topics/1
# DELETE /topics/1.json
def destroy
#topic = Topic.find(params[:id])
#topic.destroy
respond_to do |format|
format.html { redirect_to topics_url }
format.json { head :no_content }
end
end
end
Your error is caused by this line in the show action #topic.posts.build and this line in the view #topic.posts.each. Since you are building a new post in the controller, #topic.posts includes that new record which most probably have the user as nil. So the solution to your problem is to use #posts instead of #topic.posts in your view.
Check your database. Its very likely that in your database there is a post which corresponds to no user. Since the user for that post is none, the profile becomes undefined for nil:NilClass which is user(null).
This happens mostly when you creates the post that belongs to user but then you deletes the user that belongs to that post from database.
The correct way is to impose a constraint in your user model that should be-
class Post
belongs_to :user, :dependent => :destroy
end
So if the user gets deleted, the corresponding posts of that user also get deleted.
Please note that it is not a good practice to directly delete records from database after imposing the relationship between them using tables.

Rails has_many :through creating new and linking in controller

I have a website I am making that tracks a users companies through employments. I need to know what I am doing wrong because when I make a new user company the user doesn't know about it.
companies_controller.rb
class CompaniesController < ApplicationController
# GET /companies
# GET /companies.json
def index
#companies = current_user.companies
respond_to do |format|
format.html # index.html.erb
format.json { render json: #companies }
end
end
# GET /companies/1
# GET /companies/1.json
def show
#company = Company.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #company }
end
end
# GET /companies/new
# GET /companies/new.json
def new
#company = Company.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #company }
end
end
# GET /companies/1/edit
def edit
#company = Company.find(params[:id])
end
# POST /companies
# POST /companies.json
def create
#company = Company.new(params[:company])
current_user.employments.create!(company_id: #company.id)
respond_to do |format|
if #company.save
format.html { redirect_to #company, notice: 'Company was successfully created.' }
format.json { render json: #company, status: :created, location: #company }
else
format.html { render action: "new" }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# PUT /companies/1
# PUT /companies/1.json
def update
#company = Company.find(params[:id])
respond_to do |format|
if #company.update_attributes(params[:company])
format.html { redirect_to #company, notice: 'Company was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #company.errors, status: :unprocessable_entity }
end
end
end
# DELETE /companies/1
# DELETE /companies/1.json
def destroy
#company = Company.find(params[:id])
#company.destroy
respond_to do |format|
format.html { redirect_to companies_url }
format.json { head :no_content }
end
end
end
The problem is within your create action, specifically the line
current_user.employments.create!(company_id: #company.id)
this is executed before the company record is saved so it doesn't have an id (== nil). Just move that line after
if #company.save
and it should attach it to the current_user via the :through relationship.

Resources