Issues with update action using acts_as_votable - ruby-on-rails

I'm currently getting the votes to hit the database but I'm now having issues getting the update action to work in my controller. The votes don't record with the update action but do without out it. However, I then get a missing template error for Pits#update. Any help is appreciated. Thanks.
Terminal Error
Started PUT "/pits/3" for 127.0.0.1 at 2014-08-21 11:38:25 -0500
Processing by PitsController#update as JS
Parameters: {"id"=>"3"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = 4 ORDER BY "users"."id" ASC LIMIT 1
Pit Load (0.2ms) SELECT "pits".* FROM "pits" WHERE "pits"."user_id" = ? AND "pits"."id" = ? LIMIT 1 [["user_id", 4], ["id", 3]]
Completed 404 Not Found in 64ms
ActiveRecord::RecordNotFound (Couldn't find Pit with 'id'=3 [WHERE "pits"."user_id" = ?]):
app/controllers/pits_controller.rb:37:in `update'
I currently have
Pits Controller
class PitsController < ApplicationController
def new
#pit = Pit.new
end
def index
#pit = Pit.all
#user = User.find_by(params[:id])
#pits = Pit.paginate(:page => params[:page]).order('created_at ASC').group_by { |pit| pit.created_at.strftime("%B %Y") }
end
def create
#user = current_user
#pit = current_user.pits.create(pit_params)
if #pit.save
redirect_to #pit
else
render 'new'
end
end
def show
#pit = Pit.find(params[:id])
end
def edit
end
def update
#user = current_user
#pit = current_user.pits.find(params[:id])
if #pit.update_attributes(pit_params)
redirect_to #pit
end
end
private
def pit_params
params.require(:pit).permit(:topic, :summary, :image, :video_url, :author, :user_id)
end
end
Comments Controller
class CommentsController < ApplicationController
def create
#pit= Pit.find(params[:pit_id])
#comment = #pit.comments.build(comments_params)
#comment.user = current_user
#comment.save
redirect_to pit_path(#pit)
end
def destroy
#pit = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:id])
#comment.destroy
redirect_to pit_path(#pit)
end
def upvote
#pit = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:comment_id])
#comment.upvote_by current_user
redirect_to pit_path(#pit)
end
def downvote
#pit = Pit.find(params[:pit_id])
#comment = #pit.comments.find(params[:comment_id])
#comment.downvote_from current_user
redirect_to pit_path(#pit)
end
def update
end
def show
end
private
def comments_params
params.require(:comment).permit(:body, :user_id, :votable, :voter, :vote_scope)
end
end
_comment.html.erb
<div class = "well">
<p>
<strong>Comment:</strong>
<%= comment.body %>
<p>posted by: <%= comment.user.name %></p>
<%= link_to "Like", pit_comment_like_path(#pit, comment), method: :put , :remote => true %>
<%= link_to "Dislike", pit_comment_dislike_path(#pit, comment), method: :put, :remote => true %>
</p>
<p>
<%if comment.user == current_user %>
<%= link_to 'Destroy Comment', [#pit, comment],
method: :delete,
data: { confirm: 'Are you sure?' } %>
<% end %>
</p>
</div>

Not sure about everything you have going on here, but I suspect the error has to do with use current_user to find the pit. If the current_user is not the user_id for the pit, it won't find any pit (exactly your error).
Try adjusting to this and it should be able to find the pit propperly.
def update
#pit = Pit.find(pit_params[:id])
if #pit.update_attributes(pit_params)
redirect_to #pit
end

Related

RoR: Enums, how to list recipients of a message based on them

I have an application that allows a user to send a message to other users. I have two user types defined as enums in user rb- teacher and student:
enum access_level: [:student, :teacher]
I am wondering how to get the desired recipients to appear in a list in the view (below) so that a teacher can only send to students or the other way round.
In my messages controller I have:
class MessagesController < ApplicationController
before_action :authenticate_user!
def new
#chosen_recipient = User.find_by(id: params[:to].to_i) if params[:to]
end
def create
recipients = User.where(id: params['recipients'])
conversation = current_user.send_message(recipients, params[:message][:body], params[:message][:subject]).conversation
flash[:success] = "Message has been sent!"
redirect_to conversation_path(conversation)
end
end
And my conversations controller:
class ConversationsController < ApplicationController
before_action :authenticate_user!
before_action :get_mailbox
before_action :get_conversation, except: [:index, :empty_trash]
before_action :get_box, only: [:index]
def index
if #box.eql? "inbox"
#conversations = #mailbox.inbox
elsif #box.eql? "sent"
#conversations = #mailbox.sentbox
else
#conversations = #mailbox.trash
end
#conversations = #conversations.paginate(page: params[:page], per_page: 10)
end
def show
end
def mark_as_read
#conversation.mark_as_read(current_user)
flash[:success] = 'The conversation was marked as read.'
redirect_to conversations_path
end
def reply
current_user.reply_to_conversation(#conversation, params[:body])
flash[:success] = 'Reply sent'
redirect_to conversation_path(#conversation)
end
def destroy
#conversation.move_to_trash(current_user)
flash[:success] = 'The conversation was moved to trash.'
redirect_to conversations_path
end
def restore
#conversation.untrash(current_user)
flash[:success] = 'The conversation was restored.'
redirect_to conversations_path
end
def empty_trash
#mailbox.trash.each do |conversation|
conversation.receipts_for(current_user).update_all(deleted: true)
end
flash[:success] = 'Your trash was cleaned!'
redirect_to conversations_path
end
private
def get_mailbox
#mailbox ||= current_user.mailbox
end
def get_conversation
#conversation ||= #mailbox.conversations.find(params[:id])
end
def get_box
if params[:box].blank? or !["inbox","sent","trash"].include?(params[:box])
params[:box] = 'inbox'
end
#box = params[:box]
end
end
My view (messages/_form.html.erb):
<%= form_tag messages_path, method: :post do %>
<div class="form-group">
<%= label_tag 'message[subject]', 'Subject' %>
<%= text_field_tag 'message[subject]', nil, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'message[body]', 'Message' %>
<%= text_area_tag 'message[body]', nil, cols: 3, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'recipients', 'Choose recipients' %>
<%= select_tag 'recipients', recipients_options(#chosen_recipient), multiple: true, class: 'form-control chosen-it' %>
</div>
<%= submit_tag 'Send', class: 'btn btn-primary' %>
<% end %>
How would I get the list to appear based on the enum attribute associated with the user? A teacher could only see students for example.
Appreciate any guidance. Thanks.
Here are the methods given by the enum,
class User < ActiveRecord::Base
enum access_level: [ :student, :teacher ]
end
user.student!
user.student? # => true
user.access_level # => "student"
user.teacher!
user.teacher? # => true
user.access_level # => "teacher"
So you can use,
def new
if params[:to].present?
render text: params and return false
#chosen_recipient = current_user.student? ? check_access_level('teacher') : check_access_level('student')
end
end
private
def check_access_level(access_level)
User.where(id: params[:to].to_i, access_level: access_level)
end
Try this,
def new
#chosen_recipient = current_user.student? (User.where(id: params[:to].to_i, access_level: 1)) : current_user.teacher? (User.where(id: params[:to].to_i, access_level: 0)) if params[:to]
end
Have you tried changing the method that generates the chosen recipients? In helpers/messages_helpers.rb change the method as follows:
User.teacher.each do |user|
s << "leave this the way it is"
end
You can also do as Navin suggested and just check if the current user is a teacher. I would just put a variable as follows
if user.teachers?
reciepients = User.all
else
reciepients = User.teachers?
end
Then we can do as follows:
recipients.each do |user|
s << "leave this the way it is"
end
Hope that points you in the right direction.

ActionController::RoutingError (undefined local variable or method `current_order' for OrderItemsController:Class):

I'm building a store in Rails that has a specific sales model. I need to allow a user to add only 3 items to his order per 30 days. The 30 days counter should start upon adding the first order_item. Once 30 days expires, user would be able to add 3 orders. If 30 days didn't pass and for an example, user adds two order_items he would still be allowed to add one more order_item within 30 days. So as well if user tries to add more then 3 items to show an error message and disregard saving of the order_items to current_user's order.
I'm getting this error in my log right now:
ActionController::RoutingError (undefined local variable or method current_order' for OrderItemsController:Class): app/controllers/order_items_controller.rb:15:in <class:OrderItemsController>' app/controllers/order_items_controller.rb:1:in `<top (required)>''
Relevant codes:
order_items_controller.rb
class OrderItemsController < ApplicationController
def create
#item = OrderItem.new(order_item_params)
session[:order_id] = current_order.id
if #item.save
respond_to do |format|
format.js { flash[:notice] = "ORDER HAS BEEN CREATED." }
end
else
redirect_to root_path
end
end
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.user_id = current_user.id
#order.save
session[:order_id] = #order.id
end
private
def order_item_params
base_params = params.require(:order_item)
.permit(:quantity, :product_id, :user_id)
base_params.merge(order: current_order)
end
order_item.rb
class OrderItem < ActiveRecord::Base
belongs_to :product
belongs_to :order
validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0 }
validate :product_present
validate :order_present
validate :only_3_items_in_30_days
before_save :finalize
def unit_price
if persisted?
self[:unit_price]
else
product.price
end
end
def total_price
unit_price * quantity
end
private
def product_present
if product.nil?
errors.add(:product, "is not valid or is not active.")
end
end
def order_present
if order.nil?
errors.add(:order, "is not a valid order.")
end
end
def finalize
self[:unit_price] = unit_price
self[:total_price] = quantity * self[:unit_price]
end
def only_3_items_in_30_days
now = Date.new
days_since_first = now - order.first_item_added_at
if order.order_items.count > 2 && days_since_first < 30
errors.add(:base, 'only 3 items in 30 days are allowed')
end
true # this is to make sure the validation chain is not broken in case the check fails
end
end
And form that is being submitted:
<%= form_for OrderItem.new, html: {class: "add-to-cart"}, remote: true do |f| %>
<div class="input-group">
<%= f.hidden_field :quantity, value: 1, min: 1 %>
<div class="input-group-btn">
<%= f.hidden_field :product_id, value: product.id %>
<%= f.submit "Add to Cart", data: { confirm: 'Are you sure that you want to order this item for current month?'}, class: "btn btn-default black-background white" %>
</div>
</div>
<% end %>
</div>
Where are you setting your current_order?
class OrderItemsController < ApplicationController
def create
#item = OrderItem.new(order_item_params)
session[:order_id] = current_order.id
if #item.save
respond_to do |format|
format.js { flash[:notice] = "ORDER HAS BEEN CREATED." }
end
else
redirect_to root_path
end
end
# I have no idea of what this method ought to accomplish could you try to explain? but this is the immediate cause of the error. There could be others though.
def method_wrapper
#order = current_order
#order_item = #order.order_items.new(order_item_params)
#order.user_id = current_user.id
#order.save
session[:order_id] = #order.id
end
private
def order_item_params
base_params = params.require(:order_item)
.permit(:quantity, :product_id, :user_id)
base_params.merge(order: current_order)
end
end

Ruby: If last variable was saved more than 3 hours ago

I have a ruby form to submit reports for an exercise on my app. An exercise has_many reports. I want to create an if statement that makes this form only appear if the last report from that exercise was saved more than 3 hours ago.
So far I have:
But this is creating a NoMethodError saying undefined method 'report' for #<Exercise:0x007f9c892f48b0>.
It's being displayed on my workouts#show page (a workout has_many exercises, in case it helps), so I believe this is the reigning controller:
class WorkoutsController < ApplicationController
def index
#workouts = Workout.all
end
def show
#workout = Workout.find(params[:id])
#exercise = Exercise.new
#report = Report.new
end
def new
#workout = Workout.new
#workout.user_id = current_user
end
def create
#workout = Workout.new(workout_params)
#workout.user = current_user
if #workout.save
flash[:notice] = "Workout was saved successfully."
redirect_to #workout
else
flash.now[:alert] = "Error creating workout. Please try again."
render :new
end
end
def edit
#workout = Workout.find(params[:id])
end
def update
#workout = Workout.find(params[:id])
#workout.name = params[:workout][:name]
#workout.workout_type = params[:workout][:workout_type]
#workout.teaser = params[:workout][:teaser]
#workout.description = params[:workout][:description]
#workout.video = params[:workout][:video]
#workout.difficulty = params[:workout][:difficulty]
#workout.trainer = params[:workout][:trainer]
#workout.user_id = params[:workout][:user_id]
if #workout.save
flash[:notice] = "Workout was updated successfully."
redirect_to #workout
else
flash.now[:alert] = "Error saving workout. Please try again."
render :edit
end
end
def destroy
#workout = Workout.find(params[:id])
if #workout.destroy
flash[:notice] = "\"#{#workout.name}\" was deleted successfully."
redirect_to action: :index
else
flash.now[:alert] = "There was an error deleting the workout."
render :show
end
end
private
def workout_params
params.require(:workout).permit(:name, :workout_type, :teaser, :description, :video, :difficulty, :trainer, :user_id)
end
end
Any ideas where I'm going wrong?
ADDITIONAL INFORMATION:
This bit is technically on my workouts#show page:
<% if #workout.exercises.count == 0 %>
<p>Looks like you get a freebie for this one! No score report today. Rest up and drink some water. It ain't always that easy...</p>
<% else %>
<% #workout.exercises.each do |exercise| %>
<%= render 'reports/form', report: #report, exercise: exercise %>
<% if current_user.admin? %>
<div class="text-center"><%= link_to "Delete #{exercise.name}", [exercise], method: :delete, data: { confirm: 'Are you sure?' } %></div>
<% end %>
<hr>
<% end %>
But here is the partial it renders, where the code in question actually lies:
<% if exercise.report.last != nil && exercise.report.last.created_at < ( DateTime.now - (3/24.0)) %>
<%= form_for report,
:url => { :controller => "reports",
:action => :create,
:exercise_id => exercise.id } do |f| %>
<div class="row">
...
It seems you calling singularized report instead of reports.
if exercise.report.last
If reports relates to exercise as has_many you need to call it with exercise.reports.last
Also, you mentioned results in your question, but calling reports in your view.
An exercise has_many results.
...
exercise.report.last
Please be sure you calling appropriate pluralize method reports or results

Nested Routes can not index all

I have nested routes as follows;
resources :boats, except: :destroy do
resources :pictures
end
So user can upload picture and everything works fine. But picture/index.html.erb. I can not see all the pictures. It returns nil. But I can see pictures in the database. Probably because I try to retrieve wrong parameter.
When I take out the if statement <% if #pictures.present? %> it throws and error;
NoMethodError in PicturesController#create
undefined method `each' for nil:NilClass
<% #pictures.each do |pic| %>
Here is #index view;
<div class="container">
<h1>Pictures#index!</h1>
<p>Find me in app/views/pictures/index.html.erb</p>
<% if #pictures.present? %> <!-- Returns nil-->
<% #pictures.each do |pic| %>
</br>
<%= pic.name %>
<%= image_tag pic.image_url(:thumb).to_s %>
<%= link_to "edit", edit_boat_picture_path(#boat, #picture) %> |
<td><%= link_to 'Destroy', [#boat, #picture], confirm: 'Are you sure?', method: :delete %></td> |
</br>
<% end %>
<% end %>
<%= link_to "edit", edit_boat_picture_path(#boat, #picture) %> |
</br>
</br>
<%= link_to "add", new_boat_picture_path(#boat, #picture) %>
</div>
So here, picture.present returns always nil, so I can not display any images.
Here is pictures controller;
class PicturesController < ApplicationController
before_action :logged_in_user
before_filter :load_parent
def index
#pictures = #boat.pictures.all
end
def new
#picture = #boat.pictures.new
end
def show
#picture = #boat.pictures.find(params[:id])
end
def create
#picture = #boat.pictures.new(picture_params)
if #picture.save
#flash[:success] = "Continue from here"
render 'index'
#redirect_to boat_path(#boat)
else
render 'new'
end
end
def edit
#picture = Picture.find(params[:id])
end
def update
#picture = #boat.pictures.find(params[:id])
if #picture.update_attributes(picture_params)
flash[:notice] = "Successfully updated picture."
render 'index'
else
render 'edit'
end
end
def destroy
#picture = #boat.pictures.find(params[:id])
#picture.destroy
flash[:notice] = "Successfully destroyed picture."
redirect_to boat_path(#boat)
end
private
def picture_params
params.require(:picture).permit(:name, :image)
end
def load_parent
#boat = Boat.find(params[:boat_id])
end
end
EDIT 1:
Log;
{"utf8"=>"✓", "authenticity_token"=>"i3FW1zbhoGW2vavipN9NJ2Fvi9R1Lk/CKDsAttuqHWb8rFNmJgXpjE2D25oAqJ3xp9BXAnd0kDmrdIxhn1Qrpw==", "picture"=>{"name"=>"", "image"=>#<ActionDispatch::Http::UploadedFile:0x007fb4a5f50f30 #tempfile=#<Tempfile:/var/folders/w0/703ccggs56l3hrc79h3rdylm0000gn/T/RackMultipart20150423-5028-1rbpgnj.jpg>, #original_filename="imgres-4.jpg", #content_type="image/jpeg", #headers="Content-Disposition: form-data; name=\"picture[image]\"; filename=\"imgres-4.jpg\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"Done", "controller"=>"pictures", "action"=>"create", "boat_id"=>"114"}
EDIT 2:
if I add #pictures = #boat.pictures.all to create that is fine, but all pics have its own destroy button.And when I look at them all shows the same address, so clicking to destroy, destroys all of them;
All of the destroy ids are the same. I though index action lists all and destroy erases individually. This case is same for edit action too
EDIT 3:
#boats controller
class BoatsController < ApplicationController
before_action :logged_in_user, only: [:new, :show, :edit, :update]
def new
#boat = Boat.new
end
def create
#boat = current_user.boats.new(boat_params) if logged_in?
if #boat.save
#flash[:success] = "Continue from here"
render 'edit'
else
render 'new'
end
end
def show
#boat = Boat.find(params[:id])
end
def edit
#boat = Boat.find(params[:id])
end
def update
#boat = Boat.find(params[:id])
if #boat.update_attributes(boat_params)
flash[:success] = "The Boat Saved"
redirect_to root_path
else
render 'edit'
end
end
def update_years
# updates year and model based on brand selected
brand = Brand.find_by_name(params[:brand_name])
# map to name and id for use in our options_for_select
#years = brand.years.map{|a| [a.name, a.name]}.insert(0, "Select a Year") #use a.name here instead of a.id
#models = brand.models.map{|s| [s.name, s.name]}.insert(0, "Select a Model")#use s.name here instead of s.id
end
def update_models
# updates model based on year selected
year = Year.find_by_name(params[:year_name])
#models = year.models.map{|s| [s.name, s.name]}.insert(0, "Select a Model") #use s.name here instead of s.id
end
private
def boat_params
params.require(:boat).permit(:brand, :year, :model, :captained, :boat_type, :daily_price, :boat_length, :listing_tagline, :listing_description, :boat_category, :hull_material, :mast_material)
end
end
There is no #pictures in your create action.
You can try:
def create
#picture = #boat.pictures.new(picture_params)
if #picture.save
#flash[:success] = "Continue from here"
#pictures = #boat.pictures.all
render 'index'
#redirect_to boat_path(#boat)
else
render 'new'
end
end
For buttons:
<% #pictures.each do |pic| %>
</br>
<%= pic.name %>
<%= image_tag pic.image_url(:thumb).to_s %>
<%= link_to "edit", edit_boat_picture_path(#boat, pic) %> |
<td><%= link_to 'Destroy', boat_picture_path(#boat, pic), confirm: 'Are you sure?', method: :delete %></td> |
</br>
<% end %>

Find a record using form params in rails "couldn't find error"

I am new to rails. I am trying to Find a 'Category' record using a value submitted in a form field. Since I use Find by params[:id] for url parameters all the time, I thought it would work for form parameters.
This is my error
Couldn't find Category with 'id'=
on this line:
#category = Category.find(params[:category_id])
Here is my code
posts_controller.rb
def delete
#post = Post.find(params[:id])
#category = Category.find(#post.category_id)
#post_archive = PostArchive.new
end
def destroy
#post = Post.find(params[:id])
*#category = Category.find(params[:category_id])* <--the error hits here
#old_id = params[:post_id]
#author_id = params[:author_id]
#followers = Follower.find(post_id: #old_id)
#post_archive = PostArchive.new
PostArchive.create!(post_id: #old_id, author_id: #author_id , removed_by: current_user.id,
category_id: #category.id,
post_created_at: #post.created_at )
#post.destroy
#followers.each do |follower|
ProjectMailer.post_deletion(current_user, #category, #author_id, follower, #old_id ).deliver
end
#followers.destroy_all
redirect_to posts_path, notice: 'Project Deleted'
end
form
<%= form_for :delete_post, url: post_destroy_path(#post), method: :delete do |f| %>
<%= f.hidden_field :author_id#post.author_id %>
<%= f.hidden_field :category_id, #post.category_id %>
<%= f.hidden_field :post_id, value: #post.id %>
Are you sure you want to delete <%=#post.title %>?
<%=f.submit %>
<% end %>
I've tested that I can find the param using Categorgy.find(2) and I've tested that the param is actually showing up in the form (it's a hidden field....so I needed to )
server log:
Processing by PostsController#destroy as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"s2pglEj+LUIvZ8OJ0i/sbb3T8hDTcFrqdV0rJqa3c/pihtrMez4S5A8bK3NmoQ/BleKrMRuMTUhZvCwl+00jeQ==", "delete_post"=>{"author_id"=>"21", "category_id"=>"2", "post_id"=>"417"}, "commit"=>"Delete Post", "id"=>"417"}
As you can see from your params, category_id is inside delete_post
Parameters: {"delete_post"=>{"author_id"=>"21", "category_id"=>"2", "post_id"=>"417"}, "commit"=>"Delete Post", "id"=>"417"}
It should be
#category = Category.find(params[:delete_post][:category_id])
def destroy
#post = Post.find(params[:id])
*#category = Category.find(params[:category_id])* <--the error hits here
# change to
# *#category = Category.find(params[:delete_post][:category_id])*
#old_id = params[:post_id]
#author_id = params[:author_id]
#followers = Follower.find(post_id: #old_id)
#post_archive = PostArchive.new
PostArchive.create!(post_id: #old_id, author_id: #author_id , removed_by: current_user.id,
category_id: #category.id,
post_created_at: #post.created_at )
#post.destroy
#followers.each do |follower|
ProjectMailer.post_deletion(current_user, #category, #author_id, follower, #old_id ).deliver
end
#followers.destroy_all
redirect_to posts_path, notice: 'Project Deleted'
end

Resources