Ruby on Rails : undefined method `-' for nil:NilClass - ruby-on-rails

I'm trying to add save_with_initial_vote method to my Post class. It should both save the post and create its vote inside a transaction.
My post.rb looks like this:
class Post < ActiveRecord::Base
has_one :summary
has_many :comments, dependent: :destroy
has_many :votes, dependent: :destroy
belongs_to :user
belongs_to :topic
mount_uploader :image, ImageUploader
def up_votes
votes.where(value: 1).count
end
def down_votes
votes.where(value: -1).count
end
def points
votes.sum(:value)
end
def update_rank
age_in_days = (created_at - Time.new(1970,1,1)) / (60 * 60 * 24) # 1 day in seconds
new_rank = points + age_in_days
update_attribute(:rank, new_rank)
end
default_scope { order('rank DESC') }
scope :ordered_by_title, -> { order('posts.title ASC') }
scope :ordered_by_reverse_created_at, -> { order('posts.created_at DESC') }
validates :title, length: { minimum: 5 }, presence: true
validates :body, length: { minimum: 20 }, presence: true
validates :topic, presence: true
validates :user, presence: true
def markdown_title
render_as_markdown(self.title)
end
def markdown_body
render_as_markdown(self.body)
end
def create_vote
user.votes.create(value: 1, post: self)
end
def save_with_initial_vote
ActiveRecord::Base.transaction do
save
user.votes.create(value: 1, post: self)
end
end
private
def render_as_markdown(markdown)
renderer = Redcarpet::Render::HTML.new
extensions = {fenced_code_blocks: true}
redcarpet = Redcarpet::Markdown.new(renderer, extensions)
(redcarpet.render markdown).html_safe
end
end
My posts_controller.rb looks like this:
class PostsController < ApplicationController
def show
#topic = Topic.find(params[:topic_id])
authorize #topic
#post = Post.find(params[:id])
#comments = #post.comments
end
def new
#topic = Topic.find(params[:topic_id])
#post = Post.new
authorize #post
end
def edit
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
authorize #post
end
def create
#topic = Topic.find(params[:topic_id])
#post = current_user.posts.build(post_params)
authorize #post
if #post.save_with_initial_vote
flash[:notice] = "Post was saved."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :new
end
end
def update
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
authorize #post
if #post.update_attributes(post_params)
flash[:notice] = "Post was updated."
redirect_to [#topic, #post]
else
flash[:error] = "There was an error saving the post. Please try again."
render :new
end
end
def destroy
#topic = Topic.find(params[:topic_id])
#post = Post.find(params[:id])
authorize #post
if #post.destroy
flash[:notice] = "\"#{#post.title}\" was deleted."
redirect_to #topic
else
flash[:error] = "There was an error deleting your post. Please try again."
render :show
end
end
private
def post_params
params.require(:post).permit(:title, :body, :image)
end
end
My vote.rb looks like this:
class Vote < ActiveRecord::Base
belongs_to :user
belongs_to :post
validates :value, inclusion: {in: [-1, 1], message: "%{value} is not a valid vote." }
after_save :update_post
private
def update_post
post.update_rank
end
end
When I do, I get an error:
undefined method `-' for nil:NilClass

To troubleshoot your problem start by looking at the source for your error. The error says "undefined method '-' for nil:NilClass".
What this means is that you are trying to subtract from an object that is in fact Nil.
When you try to save a Vote, in vote.rb model you call update_post after save. This calls the update_rank method in the Post model. This method then subtracts a Time object from 'created_at'. The problem thus lies with created_at returning a nil value.
You can try using pry gem to debug your code better. You can then add 'binding.pry' anywhere in your model/controller code and step through each line to see what is the value of each variable at that instant.

Related

NoMethodError in EventsController#create undefined method `build' for nil:NilClass?

I'm getting a bit confused as to why I am receiving this error as (i think) it is suggesting that my current_customer returns nil. I do not know how to fix this, is it a problem with my current_customer method, sessions controller, or my events_controller...
Event Model:
class Event < ActiveRecord::Base
belongs_to :calendar
end
Events Controller:
class EventsController < ApplicationController
def new
#event = Event.new
#calendar = current_customer.calendar #WHY IS IT NOT ERRORING HERE TOO?
end
def create
**#calendar = current_customer.calendar #IT IS CALLING ERROR HERE**
#event = #calendar.build.event(event_params)
if #event.save
redirect_to '/main'
else
redirect_to '/compose'
end
end
private
def event_params
params.require(:event).permit(:calendar_id, :name, :starts_at, :ends_at)
end
Customer model:
class Customer < ActiveRecord::Base
belongs_to :business
has_one :calendar
has_secure_password
attr_accessor :remember_token
#remembers a user in the database for use in persistent sessions
def remember
self.remember_token = Customer.new_token
update_attribute(:remember_digest, Customer.digest(remember_token))
end
def Customer.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
def forget
update_attribute(:remember_digest, nil)
end
def Customer.new_token
SecureRandom.urlsafe_base64
end
#returns true if the given token matches the digest
def authenticated?(remember_token)
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
end
Customer controller:
class CustomersController < ApplicationController
def new
#customer = Customer.new
#businesses = Business.all
#calendar = Calendar.new
end
def create
#customer = Customer.create(customer_params)
#calendar = #customer.build_calendar
#customer.save!
session[:customer_id] = #customer.id
redirect_to '/'
rescue ActiveRecord::RecordInvalid => ex
render action: 'new', alert: ex.message
end
private
def customer_params
params.require(:customer).permit(:first_name, :last_name, :business_no, :email, :password, :business_id)
end
end
Sessions controller:
class SessionsController < ApplicationController
def new
end
def create
#customer = Customer.find_by_email(params[:session][:email])
if #customer && #customer.authenticate(params[:session][:password])
session[:customer_id] = #customer.id #log in
#customer.remember
cookies.permanent.signed[:customer_id] = #customer.id
cookies.permanent[:remember_token] = #customer.remember_token
redirect_to '/main'
else
#need to add flash error: invalid password/email combination
redirect_to '/login'
end
end
def destroy
#current_customer.forget
cookies.delete(:customer_id)
cookies.delete(:remember_token)
session.delete(:customer_id)
#current_customer = nil
redirect_to '/'
end
end
Current_customer method within application.controller:
helper_method :current_customer
def current_customer
if (customer_id = session[:customer_id])
#current_customer ||= Customer.find_by(id: customer_id)
elsif (customer_id = cookies.signed[:customer_id])
customer = Customer.find_by(id: customer_id)
if customer && customer.authenticated?(cookies[:remember_token])
session[:customer_id] = customer.id #log in
#current_customer = customer
end
end
end
Calendar model:
class Calendar < ActiveRecord::Base
belongs_to :customer
has_many :events
end
calendars_controller:
class CalendarsController < ApplicationController
def new
#calendar = Calendar.new(calendar_params)
end
def create
#calendar = Calendar.new(calendar_params)
end
private
def calendar_params
params.require(:customer_id)
end
end
I am new to Ruby/Rails so I would really appreciate any explanations and answers, please help! thanks
#calendar = current_customer.calendar
#event = #calendar.build.event(event_params)
According to the error message, #calendar is nil, so when you call #calendar.build.event(event_params) in the next line, it calls: nil.build and hence you get the error.
For some reason, your current_customer's calendar is nil for that request. Figure that out and make sure the current_customer has a calendar present in the database, then it should work.
Also, you need to change:
#event = #calendar.build.event(event_params)
To:
#event = #calendar.events.build(event_params)
It would seem that #calendar is nil in the events controller.
Start by checking the current_customer passes back the customer you were expecting.
Then check that the current_customer has a calendar created for you to reference.

Ruby On Rails Nokogiri gem importing orders from xml working not fully. Possibly permitted perimeters

I'm having some trouble with Nokogiri.
I'm new to this xml parsing and I seem to get no errors. I get the order imported alert.
Which means it may be permitted perimeters. If I'm right then, Could I create a model that allows all permitted perimeters. So please take a look, thank you for your time, here is my code:
Routes.rb
resources :orders do
collection { post :import }
get "/confirm" => "confirmations#show"
get 'dconfirmation' => 'orders#confirmation'
end
Model
class Order < ActiveRecord::Base
belongs_to :user
scope :not_completed_orders, -> {
where(:complete => false)
}
require 'nokogiri'
def self.import(file)
doc = Nokogiri::XML.parse(file)
#your processing code goes here
end
end
Controller Order
class OrdersController < ApplicationController
before_filter :authenticate_user!
def new
#order = Order.new
end
def create
#order = current_user.orders.new(order_params)
#order.email = current_user.email
#order.name = current_user.name
#order.address_line_1 = current_user.address_line_1
#order.address_line_2 = current_user.address_line_2
#order.postcode = current_user.postcode
#order.city = current_user.city
#order.country = current_user.country
if #order.save
redirect_to dconfirmation_path
end
end
def order_params
params.require(:order).
permit(
:email,
:delivery_name,
:company_name,
:delivery_address1,
:delivery_address2,
:delivery_address3,
:delivery_city,
:delivery_postcode,
:delivery_country,
:phone,
:package_contents,
:description_content,
:restricted_items,
:terms_conditions,
:insurance,
:contents_value,
:cf_reference,
:reference_number,
:service
)
end
def show
#user = User.find(params[:id])
end
def confirmation
end
def import
Order.import(params[:file])
redirect_to root_url, notice: "Order imported."
end
end
View
= form_tag import_orders_path, multipart: true do
= file_field_tag :file
= submit_tag "Import"

Syntax Error: Unexpected '(', expecting '}'

I am having some trouble with my new public/private topic methods. I need to be able to apply a publicly_viewable method to my topics scope. However, I keep getting the following error:
SyntaxError in TopicsController#index
/Users/ericpark/rails_projects/bloccit-2/app/models/topic.rb:7: syntax error, unexpected '(', expecting '}' scope :visible_to, -> { :publicly_viewable(user) } ^ /Users/ericpark/rails_projects/bloccit-2/app/models/topic.rb:20: syntax error, unexpected keyword_end, expecting '}'
Extracted source (around line #7):
5
6
7
8
9
10
validates :name, length: {minimum: 5}, presence: true
scope :visible_to, -> { :publicly_viewable(user) }
def publicly_viewable(user)
if user
I have also defined the publicly_viewable method within my topic model:
class Topic < ActiveRecord::Base
has_many :posts, dependent: :destroy
belongs_to :user
validates :name, length: {minimum: 5}, presence: true
scope :visible_to, -> { :publicly_viewable(user) }
def publicly_viewable(user)
if user
topic_collection.all
else
topic_collection.where(public: true)
end
end
def privately_viewable
topic_collection.where(public: false)
end
end
Topics Controller:
class TopicsController < ApplicationController
def index
#topics = Topic.visible_to(current_user).paginate(page: params[:page], per_page: 10)
authorize #topics
end
def show
#topic = Topic.find(params[:id])
#posts = #topic.posts.paginate(page:params[:page])
authorize #topic
end
def new
#topic = Topic.new
authorize #topic
end
def edit
#topic = Topic.find(params[:id])
authorize #topic
end
def create
#topic = Topic.new(topic_params)
authorize #topic
if #topic.save
redirect_to #topic, notice: "Topic was saved successfully."
else
flash[:error] = "Error creating topic. Please try again."
render :new
end
end
def update
#topic = Topic.find(params[:id])
authorize #topic
if #topic.update_attributes(topic_params)
redirect_to #topic
else
flash[:error] = "Error saving topic. Please try again."
render :edit
end
end
def destroy
#topic = Topic.find(params[:id])
authorize #topic
if #topic.destroy
flash[:notice] = "\"#{#topic.name}\" was deleted successfully."
redirect_to topics_path
else
flash[:error] = "There was an error deleting the topic."
render :show
end
end
private
def topic_params
params.require(:topic).permit(:name, :description, :public)
end
end
I am still quite new to scopes so anytime will be greatly appreciated.

undefined local variable or method `new_comment`

NameError in Comments#create
Showing /comments/_form.html.erb
where line #1 raised:
undefined local variable or method new_comment for #<#:0x007fb9760eb640>
<%= form_for new_comment, url: send(create_url, new_comment.commentable) do |f| %>
new_comment is being called by:
activities/index.html.erb
<%= render "comments/form", new_comment: Comment.new(commentable_id: activity.id, commentable_type: activity.class.model_name), create_url: :activity_comments_path %>
comment.rb
class Comment < ActiveRecord::Base
after_save :create_notification #ERROR OCCURRED WHEN I INTRODUCED THIS LINE AND
validates :activity, presence: true #THIS LINE
validates :user, presence: true
has_many :notifications
belongs_to :commentable, polymorphic: true
belongs_to :user
belongs_to :activity
private
def create_notification
Notification.create(
activity_id: self.activity_id,
user_id: self.user_id,
comment_id: self.id,
read: false
)
end
end
notification.rb
class Notification < ActiveRecord::Base
belongs_to :activity
belongs_to :comment
belongs_to :user
end
activity.rb
class Activity < ActiveRecord::Base
self.per_page = 20
has_many :notifications
belongs_to :user
has_many :comments, as: :commentable
belongs_to :trackable, polymorphic: true
def conceal
trackable.conceal
end
def page_number
(index / per_page.to_f).ceil
end
private
def index
Activity.order(created_at: :desc).index self
end
end
routes.rb
resources :activities do
resources :comments
resources :notifications
member do
post :like
post :notifications
end
end
Any ideas on what maybe the cause? This error is coming off of the awesome answer here: How to make a path to a paginated url?
Thank you!
UPDATE
class CommentsController < ApplicationController
before_action :load_commentable
before_action :set_comment, only: [:show, :edit, :update, :destroy, :like]
before_action :logged_in_user, only: [:create, :destroy]
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comment_params)
if #comment.save
redirect_to #commentable, notice: "comment created."
else
render :new
end
end
def edit
#comment = current_user.comments.find(params[:id])
end
def update
#comment = current_user.comments.find(params[:id])
if #comment.update_attributes(comment_params)
redirect_to #commentable, notice: "Comment was updated."
else
render :edit
end
end
def destroy
#comment = current_user.comments.find(params[:id])
#comment.destroy
redirect_to #commentable, notice: "comment destroyed."
end
def like
#comment = Comment.find(params[:id])
#comment_like = current_user.comment_likes.build(comment: #comment)
if #comment_like.save
#comment.increment!(:likes)
flash[:success] = 'Thanks for liking!'
else
flash[:error] = 'Two many likes'
end
redirect_to(:back)
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def load_commentable
resource, id = request.path.split('/')[1, 2]
#commentable = resource.singularize.classify.constantize.find(id)
end
def comment_params
params[:comment][:user_id] = current_user.id
params.require(:comment).permit(:content, :commentable, :user_id, :like)
end
end
notifications_controller
class NotificationsController < ApplicationController
def index
#notifications = current_user.notifications
#notifications.each do |notification|
notification.update_attribute(:read, true)
end
end
def destroy
#notification = Notification.find(params[:id])
#notification.destroy
redirect_to :back
end
end
activities_controller
class ActivitiesController < ApplicationController
def index
#activities = Activity.order("created_at desc").paginate(:page => params[:page])
end
def show
redirect_to(:back)
end
def like
#activity = Activity.find(params[:id])
#activity_like = current_user.activity_likes.build(activity: #activity)
if #activity_like.save
#activity.increment!(:likes)
flash[:success] = 'Thanks for liking!'
else
flash[:error] = 'Two many likes'
end
redirect_to(:back)
end
end
It should be <%= form_for comment do |f| %> not new comment since comment is the element in your database

ActiveRecord::RecordNotSaved - Forcing nested redirect

Morning All,
After spending most of the night figuring out how to put a limit on my model creation I finally got somewhere. The nested statement is now presenting me with not saved which is great news.
However I cannot seem to get the redirect or flash[:base] to work. Here is the code below:
class SnippetsController < ApplicationController
before_filter :find_book
def create
if #snippet = #book.snippets.create!(params[:snippet])
redirect_to #book
else
flash[:base]
#render
end
end
def approve
##snippet = #book.snippet.find(params[:id])
if #snippet.update_attribute(:approved, true)
redirect_to users_path
else
render root_path
end
end
def edit
#snippet = #book.snippets.find(params[:id])
end
def update
#snippet = #book.snippets.find(params[:id])
respond_to do |format|
if #snippet.update_attributes(params[:snippet])
format.html { redirect_to #book, notice: 'Comment was successfully updated.' }
else
format.html { render action: "edit" }
end
end
end
private
def find_book
#book = Book.find(params[:book_id])
end
end
Models parent (book)
class Book < ActiveRecord::Base
has_many :snippets
attr_accessible :title, :book_id, :size
def snippets_limit_reached?
if size == 0
self.snippets.count >= 2
elsif size == 1
self.snippets.count >= 3
elsif size == 2
self.snippets.count >= 4
else
return false
end
end
end
Child (Snippet)
class Snippet < ActiveRecord::Base
before_create :check_limit
belongs_to :book
attr_accessible :content, :book_id
validates :book_id, presence: true
def check_limit
if book.snippets_limit_reached?
errors.add :base, 'Snippet limit reached.'
return false
end
return true
end
end
Let me know if you need anything else, just fyi when it's running I cannot get past the nested create!
if #snippet = #book.snippets.create!(params[:snippet])
Bang methods (create!, save!) throw errors when unsuccessful, instead of returning, what evaluates to false.
Removing the bang should fix this problem.

Resources