I've created an activity model and I'm trying to have it so that when a user deletes their activity it also deletes the corresponding status. I've been able to do it when deleting the status, it deletes the activity but not sure how to do it in the opposite direction. I tried finding the status by targetable_id but I get:
undefined method `find_by_targetable_id' for #<Class:0x8df4a70>
Parameters:
{"_method"=>"delete",
"authenticity_token"=>"s2wKOZxCBVarT5uge3AIFNXHepFuvNGM+kU/q+ArOjA=",
"id"=>"18"}
If you're familiar with the public_activity gem then targetable is the same thing as trackable and in this example, the activity id is 18 and it's corresponding status id is 53
ActivitiesController
class ActivitiesController < ApplicationController
before_filter :authenticate_member!, only: [:destroy]
before_filter :find_activity, only: [:destroy]
def index
following_ids = current_member.following_members.map(&:id)
#activities = Activity.where("member_id in (?)", following_ids.push(current_member.id)).order("created_at desc").all
end
def destroy
#status = Activity.targetable
if #status
#status.destroy
end
#activity.destroy
respond_to do |format|
format.html { redirect_to :back }
format.json { head :no_content }
end
end
private
def find_activity
#activity = current_member.activities.find(params[:id])
end
end
StatusesController
class StatusesController < ApplicationController
before_filter :authenticate_member!, only: [:new, :create, :edit, :update, :destroy]
before_filter :find_member
before_filter :find_status, only: [:edit, :update, :destroy, :show]
rescue_from ActiveRecord::RecordNotFound do
render file: 'public/404', status: 404, formats: [:html]
end
# GET /statuses
# GET /statuses.json
def index
#statuses = Status.order('created_at desc').all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #statuses }
end
end
# GET /statuses/1
# GET /statuses/1.json
def show
respond_to do |format|
format.html # show.html.erb
format.json { redirect_to profile_path(current_member) }
end
end
# GET /statuses/new
# GET /statuses/new.json
def new
#status = Status.new
#status.build_document
respond_to do |format|
format.html # new.html.erb
format.json { render json: #status }
end
end
# GET /statuses/1/edit
def edit
end
# POST /statuses
# POST /statuses.json
def create
#status = current_member.statuses.new(params[:status])
respond_to do |format|
if #status.save
current_member.create_activity(#status, 'created')
format.html { redirect_to :back }
format.json
else
format.html { redirect_to profile_path(current_member), alert: 'Post wasn\'t created. Please try again and ensure image attchments are under 10Mbs.' }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# PUT /statuses/1
# PUT /statuses/1.json
def update
if params[:status] && params[:status].has_key?(:user_id)
params[:status].delete(:user_id)
end
respond_to do |format|
if #status.update_attributes(params[:status])
format.html { redirect_to profile_path(current_member), notice: 'Status was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #status.errors, status: :unprocessable_entity }
end
end
end
# DELETE /statuses/1
# DELETE /statuses/1.json
def destroy
#activity = Activity.find_by_targetable_id(params[:id])
if #activity
#activity.destroy
end
#status.destroy
respond_to do |format|
format.html { redirect_to :back }
format.json { head :no_content }
end
end
private
def find_member
#member = Member.find_by_user_name(params[:user_name])
end
def find_status
#status = current_member.statuses.find(params[:id])
end
def sortable_date
created_at
end
end
Should not this line
#status = Activity.targetable
be
#status = #activity.targetable
?
Second note: it probably will be better to move status destroying to Activity model before_destroy callback.
Related
I'm working on a project, and for the life of me, I'm not sure what's going on. My code was working earlier, now I'm getting
NoMethodError in MoviesController#upvote
When I try and vote on a certain movie, here is my "movie_controller.rb"
class MoviesController < ApplicationController
before_action :set_movie, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
before_action :authenticate_user!
# GET /movies
# GET /movies.json
def index
#movies = Movie.all
end
# GET /movies/1
# GET /movies/1.json
def show
end
# GET /movies/new
def new
#movie = Movie.new
end
# GET /movies/1/edit
def edit
end
# POST /movies
# POST /movies.json
def create
#movie = Movie.new(movie_params)
respond_to do |format|
if #movie.save
format.html { redirect_to #movie, notice: 'Movie was successfully created.' }
format.json { render :show, status: :created, location: #movie }
else
format.html { render :new }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /movies/1
# PATCH/PUT /movies/1.json
def update
respond_to do |format|
if #movie.update(movie_params)
format.html { redirect_to #movie, notice: 'Movie was successfully updated.' }
format.json { render :show, status: :ok, location: #movie }
else
format.html { render :edit }
format.json { render json: #movie.errors, status: :unprocessable_entity }
end
end
end
# DELETE /movies/1
# DELETE /movies/1.json
def destroy
#movie.destroy
respond_to do |format|
format.html { redirect_to movies_url, notice: 'Movie was successfully destroyed.' }
format.json { head :no_content }
end
end
def upvote
#movie.upvote_from current_user
redirect_to movies_path
end
def downvote
#movie.downvote_from current_user
redirect_to movies_path
end
private
def set_movie
#movies = Movie.find(params[:movie_id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def movie_params
params.require(:movie).permit(:title, :image)
end
end
In particular it's saying there's a problem with is line:
private
def set_movie
#movies = Movie.find(params[:id])
end
I'll also attach my routes for good measure. Thank you guys.
Rails.application.routes.draw do
devise_for :users
root 'home#index'
resources :movies do
put "like", to: "movies#upvote"
put "unlike", to: "movies#downvote"
end
end
The problem is that you are setting a #movies variable instead of #movie. That's why you are getting a undefined method upvote_from' for nil:NilClass def upvote #movie.upvote_from
Change this part of the code
private
def set_movie
#movies = Movie.find(params[:id])
end
to this
private
def set_movie
#movie = Movie.find(params[:id])
end
I have a list of posts and all of them can be votable. I can count the number of votes for each post, but how can I count the number for all of them? I'm using the gem acts_as_votable for the voting system
I count the number of posts like this: <%= performance_indicator.improvement_actions.count %>
this is my "posts" controller:
class ImprovementActionsController < ApplicationController
before_action :set_improvement_action, only: [:show, :edit, :update, :destroy, :upvote, :downvote]
before_action :authenticate_user!, except: [:index, :show]
# GET /improvement_actions
# GET /improvement_actions.json
def index
end
# GET /improvement_actions/1
# GET /improvement_actions/1.json
def show
end
# GET /improvement_actions/new
def new
#performance_indicator = PerformanceIndicator.find(params[:performance_indicator_id])
#improvement_action = ImprovementAction.new
#comment = #improvement_action.comments.new
end
# GET /improvement_actions/1/edit
def edit
end
# POST /improvement_actions
# POST /improvement_actions.json
def create
#performance_indicator = PerformanceIndicator.find(params[:performance_indicator_id])
#improvement_action = #performance_indicator.improvement_actions.create(params[:improvement_action].permit(:description))
#improvement_action.user_id = current_user.id if current_user
#improvement_action.save
respond_to do |format|
if #improvement_action.save
format.html { redirect_to #performance_indicator }
format.json { render :show, status: :created, location: #improvement_action }
else
format.html { render :new }
format.json { render json: #improvement_action.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /improvement_actions/1
# PATCH/PUT /improvement_actions/1.json
def update
respond_to do |format|
if #improvement_action.update(improvement_action_params)
format.html { redirect_to performance_indicator_path(#improvement_action.performance_indicator), notice: 'Improvement action was successfully updated.' }
format.json { render :show, status: :ok, location: #performance_indicator }
else
format.html { render :edit }
format.json { render json: #improvement_action.errors, status: :unprocessable_entity }
end
end
end
def destroy
#improvement_action.destroy
respond_to do |format|
format.html { redirect_to performance_indicator_path(#improvement_action.performance_indicator), notice: 'Improvement action was successfully deleted.' }
format.json { head :no_content }
end
end
#upvote_from user
#downvote_from user
def upvote
#improvement_action.upvote_from current_user
# respond_to do |format|
# format.html { redirect_to :back }
# format.js { render layout: false }
# end
redirect_to :back
end
def downvote
#improvement_action.downvote_from current_user
redirect_to :back
##respond_to do |format|
# format.html { redirect_to :back }
# format.js { render layout: false }
# end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_improvement_action
#improvement_action = ImprovementAction.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def improvement_action_params
params.require(:improvement_action).permit(:description, :upvote, :downvote, :score, :active)
end
end
And I want to put here the counter:
<% #performance_indicators.each do |performance_indicator| %>
<p> Number of votes </p>
<% end %>
Do you have any cache column for votes in the ImprovementAction model? (https://github.com/ryanto/acts_as_votable#caching)
It is for keeping total amount of votes for each post. You should have it to do the calculation you want:
# in this case the cache column is :cached_votes_total
sum = performance_indicator.improvement_actions.sum(:cached_votes_total)
This will make only one database request.
Never do like this:
# DON'T DO THIS !!!
performance_indicator.improvement_actions.inject(0) {|sum, post| sum + post.votes_for.size }
This will have to load and instantiate all the records and make a separate request for each of them to retrieve their votes. Very BAD solution !
I'm trying to build a shopping cart that is assigned to a user. What happens now though is when an item is added to the shopping cart, it's added for every user. It seems every user is using the same cart and I can't get users from being able to add to to other users carts. How can I make it so that each user has a unique cart and can only add to theirs?
Here's what I have:
class CartsController < ApplicationController
before_action :set_cart, only: [:show, :edit, :update, :destroy]
before_action :logged_in_user, only: [:create, :edit, :update, :destroy, :show]
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
# GET /carts
# GET /carts.json
def index
#carts = Cart.all
end
# GET /carts/1
# GET /carts/1.json
def show
end
# GET /carts/new
def new
#cart = Cart.new
end
# GET /carts/1/edit
def edit
end
# POST /carts
# POST /carts.json
def create
#cart = Cart.new(cart_params)
respond_to do |format|
if #cart.save
format.html { redirect_to #cart, notice: 'Cart was successfully created.' }
format.json { render action: 'show', status: :created, location: #cart }
else
format.html { render action: 'new' }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /carts/1
# PATCH/PUT /carts/1.json
def update
respond_to do |format|
if #cart.update(cart_params)
format.html { redirect_to #cart, notice: 'Cart was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #cart.errors, status: :unprocessable_entity }
end
end
end
# DELETE /carts/1
# DELETE /carts/1.json
def destroy
#cart.destroy if #cart.id == session[:cart_id]
session[:cart_id] = nil
respond_to do |format|
format.html { redirect_to store_url, notice: "Your cart is currently empty" }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_cart
#cart = Cart.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def cart_params
params[:cart]
end
def invalid_cart
logger.error "Attempt to access invalid cart #{params[:id]}"
redirect_to store_url, notice: "Invalid Cart"
end
end
current_cart.rb
module CurrentCart
extend ActiveSupport::Concern
private
def set_cart
#cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
#cart = Cart.create
session[:cart_id] = #cart.id
end
end
line_item_controller.rb
class LineItemsController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:new, :create]
before_action :set_line_item, only: [:show, :edit, :update, :destroy]
# GET /line_items
# GET /line_items.json
def index
#line_items = LineItem.all
end
# GET /line_items/1
# GET /line_items/1.json
def show
end
# GET /line_items/new
def new
#line_item = LineItem.new
end
# GET /line_items/1/edit
def edit
end
# POST /line_items
# POST /line_items.json
def create
product = Product.find(params[:product_id])
#line_item = #cart.add_product(product: product)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render action: 'show', status: :created, location: #line_item }
else
format.html { render action: 'new' }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /line_items/1
# PATCH/PUT /line_items/1.json
def update
respond_to do |format|
if #line_item.update(line_item_params)
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
# DELETE /line_items/1
# DELETE /line_items/1.json
def destroy
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_line_item
#line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def line_item_params
params.require(:line_item).permit(:product_id )
end
end
Instead of Cart.create and Cart.find in CurrentCart.rb, you should do something like:
def set_cart
#cart = current_user.carts.find_by(id: session[:cart_id]) || current_user.carts.create
session[:cart_id] = #cart.id
end
find_by doesn't throw an error if it can't find it; it just returns nil, so you don't have to worry about rescuing.
Users can create guides only when they're logged in.
When I click on the 'New Guide' link, this is what Heroku's log puts out:
2013-12-30T20:28:37.826032+00:00 app[web.1]: ActiveRecord::UnknownAttributeError (unknown attribute: user_id):
GuidesController:
class GuidesController < ApplicationController
before_action :set_guide, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
# GET /guides
# GET /guides.json
def index
if params[:tag]
#guides = Guide.tagged_with(params[:tag])
else
#guides = Guide.all
end
end
# GET /guides/1
# GET /guides/1.json
def show
end
# GET /guides/new
def new
#guide = current_user.guides.build(guide_params)
end
# GET /guides/1/edit
def edit
end
# POST /guides
# POST /guides.json
def create
#guide = current_user.guides.build(guide_params)
respond_to do |format|
if #guide.save
format.html { redirect_to #guide, notice: 'Guide was successfully created.' }
format.json { render action: 'show', status: :created, location: #guide }
else
format.html { render action: 'new' }
format.json { render json: #guide.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /guides/1
# PATCH/PUT /guides/1.json
def update
respond_to do |format|
if #guide.update(guide_params)
format.html { redirect_to #guide, notice: 'Guide was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #guide.errors, status: :unprocessable_entity }
end
end
end
# DELETE /guides/1
# DELETE /guides/1.json
def destroy
#guide.destroy
respond_to do |format|
format.html { redirect_to guides_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_guide
#guide = Guide.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def guide_params
params.require(:guide).permit(:title, :author, :description, :link, :tag_list) if params[:guide]
end
end
You have this in your new action
def new
#guide = current_user.guides.build(guide_params)
end
Why? The new action should just return the form to the browser to create a new guide. You repeat this in your create action, where it should be.
Also your index has this:
def index
if params[:tag]
#guides = Guide.tagged_with(params[:tag])
else
#guides = Guide.all
end
end
You should probably be using guide_params[:tag] since the :tag is being returned by the browser.
EDIT I see you are using [:tag_list] in your whitelist. I assume you are handing that somewhere else? Have you tested the ability to do an index action with a tag defined? I think the only place you want to use bare params[:xxxx] is in a private method.
I have a Listings Controller where Users can Create their Listings.
To prevent users to edit other users listings i just had to update every action from
Listing to current_user.listings
but with Rails 4 the controller got changed and i can't find how to set this up.
My Controller File->
class ListingsController < ApplicationController
before_action :set_listing, only: [:show, :edit, :update, :destroy]
before_filter :authenticate_user!, :only => [:index]
# GET /listings
# GET /listings.json
def index
#listings = Listing.all
end
# GET /listings/1
# GET /listings/1.json
def show
end
# GET /listings/new
def new
#listing = Listing.new
end
# GET /listings/1/edit
def edit
end
# POST /listings
# POST /listings.json
def create
#listing = Listing.new(listing_params)
respond_to do |format|
if #listing.save
format.html { redirect_to #listing, notice: 'Listing was successfully created.' }
format.json { render action: 'show', status: :created, location: #listing }
else
format.html { render action: 'new' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /listings/1
# PATCH/PUT /listings/1.json
def update
respond_to do |format|
if #listing.update(listing_params)
format.html { redirect_to #listing, notice: 'Listing was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #listing.errors, status: :unprocessable_entity }
end
end
end
# DELETE /listings/1
# DELETE /listings/1.json
def destroy
#listing.destroy
respond_to do |format|
format.html { redirect_to listings_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_listing
#listing = Listing.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def listing_params
params.require(:listing).permit(:title, :description)
end
end
Anyone knows a Solution ?
change from #new to build. So, change all #listing = Listing.new to:
#listing = current_user.listings.build
Then, in set_listing change to:
#listing = current_user.listings.find(params[:id])