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.
Related
models/collaborators.rb:
class Collaborator < ActiveRecord::Base
belongs_to :user
belongs_to :wiki
def wiki_collaborations
end
end
controllers/wikis_controller.rb:
class WikisController < ApplicationController
def index
#user = current_user
if #user.admin?
#wikis = Wiki.all
elsif #user.premium?
#wikis = Wiki.where(private: false) | #user.wiki_collaborations | #user.wikis
elsif #user.standard?
#wikis = Wiki.where(private: false) | #user.wiki_collaborations
else
#wikis = Wiki.where(private: false)
end
end
def show
#wiki = Wiki.find(params[:id])
authorize #wiki
end
def new
#wiki = Wiki.new
end
def create
#wiki = current_user.wikis.new(wiki_params)
if #wiki.save
flash[:notice] = "Wiki was saved."
redirect_to #wiki
else
flash.now[:alert] = "There was an error saving the wiki. Please try again."
render :new
end
end
def edit
#user = current_user
#wiki = Wiki.find(params[:id])
#user_emails = User.where.not(id: current_user.id || #wiki.users.pluck(:id)).map(&:email)
authorize #wiki
end
def update
#wiki = Wiki.find(params[:id])
authorize #wiki
if #wiki.update(wiki_params)
flash[:notice] = "Wiki was updated."
redirect_to #wiki
else
flash.now[:alert] = "There was an error saving the wiki page. Please try again."
render :edit
end
end
def destroy
#wiki = Wiki.find(params[:id])
if #wiki.destroy
flash[:notice] = "\"#{#wiki.title}\" was deleted successfully."
redirect_to wikis_path
else
flash.now[:alert] = "There was an error deleting the wiki page."
render :show
end
end
private
def wiki_params
params.require(:wiki).permit(:title, :body, :private)
end
end
I tried to access http://localhost:3000/wikis.
I get the following error.
Possibly you've not defined wiki_collaborations method for user.
You can delegate it to User like,
class User < ActiveRecord::Base
delegate :wiki_collaborations, to: :collaborator
end
Btw, be aware of | is not same as ||.
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
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.
So that multiple people can be an administrator to a business page, we've created a model called administration where people can apply to be an admin of a business and thus the status of "0" is "pending" and "1" is accepted.
How can I prevent users from editing a page where their status for i is still "0" (pending).
class Administration < ActiveRecord::Base
attr_accessible :business_id, :user_id, :status
belongs_to :user
belongs_to :business
scope :pending, where('status = ?',0).order("updated_at desc")
def self.new_by_user_business( user, business)
admin = self.new
admin.business_id = business.id
admin.user_id = user.id
admin.status = 0
admin.save!
end
end
Here is the current "edit page"
<h1>Editing business</h1>
<%= render 'form1' %>
Here is the business controller.
class BusinessesController < ApplicationController
respond_to :html, :xml, :json
before_filter :authenticate_user!, except: [:index, :show]
def index
#businesses = Business.all
respond_with(#businesses)
end
def show
#business = Business.find(params[:id])
if request.path != business_path(#business)
redirect_to #business, status: :moved_permanently
end
end
def new
#business = Business.new
3.times { #business.assets.build }
respond_with(#business)
end
def edit
#business = get_business(params[:id])
#avatar = #business.assets.count
#avatar = 3-#avatar
#avatar.times {#business.assets.build}
end
def create
#business = Business.new(params[:business])
if #business.save
redirect_to #business, notice: 'Business was successfully created.'
else
3.times { #business.assets.build }
render 'new'
end
end
def update
#business = get_business(params[:id])
if #business.update_attributes(params[:business])
flash[:notice] = "Successfully updated Business."
end
#avatar = #business.assets.count
#avatar = 3-#avatar
#avatar.times {#business.assets.build}
respond_with(#business)
end
def destroy
#business = get_business(params[:id])
#business.destroy
respond_with(#business)
end
def my_business
#business = Business.all
end
def business_tickets
#user = current_user
#business = get_business(params[:id])
#tickets = #business.tickets
#business_inbox = TicketReply.where(:email => #business.callred_email)
end
def your_business
#user = current_user
#business = get_business(params[:id])
if #business.users.map(&:id).include? current_user.id
redirect_to my_business_businesses_path, notice: 'You are already an administator of this business.'
else
#admin = Administration.new_by_user_business( #user, #business)
BusinessMailer.delay(queue: "is_your_business", priority: 20, run_at: 5.minutes.from_now).is_your_business(#user,#business)
redirect_to #business, notice: 'Thank you for claiming your business, and we will be in touch with you shortly.'
end
end
def view_message
# #business = Business.find(params[:business_id])
#ticket = Ticket.find(params[:id])
#reply = #ticket.ticket_replies
end
private
def get_business(business_id)
#business = Business.find(business_id)
end
end
You could add a before_filter to check the status. You will have to change some of the logic but this is the idea
class BusinessesController < ApplicationController
before_filter :restrict_access, :only => [:edit, :update]
private
def restrict_access
#business = get_business(params[:id])
redirect to root_path, :notice => "Not Authorized" unless current_user.status == 1
end
end
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.