Stopping creation of posts unless approved is true - ruby-on-rails

Afternoon All,
I have a model called snippet.rb and I would like only one user to post at a time until approved.
Would I run this as a custom validation or as an after_create in the snippet.rb.
The step process is below:
User creates snippet
Snippet submitted for approval
No other snippets can be created until the previous one has been approved.
Could someone help me or point me in the direction of some documentation on how to do this.
Always appreciate the help. I'm trying to work through this in my head but cannot find anything to help.

in your snippets_controller.rb
before_filter :check_last_snippet, :only => [:create]
private
def check_last_snippet
redirect_to root_path unless Snippet.last.approved?
end

I believe that you should use custom validation.
for example
validate :verify_for_not_approved_snippets
def verify_for_not_aproved_posts
errors.add(:base, "error message") if "your condition here"
end
more detaily you can read at http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#performing-custom-validations

create a method in your user model and call this method before creating snippet
def check_snippet
return true if user.snippets.blank? || (user.snippets.present? && user.snippets.where(approved: true).size > 1)
end
If this method returns true then only user can post snippet again. It may help you.

You can use validate on create,
validate :check_last_snippet_approved, :on => :create
def check_last_snippet_approved
errors.add(:base, "could not add due to last snippet not approved") if !self.last.nil? && self.last.approved == false
end

Related

Ruby on Rails | How to apply validation on rails form

I am adding the promo code option for my application. I want to apply validation on the form that will match the entered promo code by the user to the promo code that has been already there in the admin dashboard (Activeadmin is used for admin dashboard).
I have tried a few options but nothing works. Examples that I have tried -
def validate_promo_code
if promo_code.present? and (!promo_code.match(EngineName::PromoCode.promo_code))
errors.add :promo_code, "must be a valid promo code"
end
end
def validate_promo_code
if promo_code.present? and (promo_code != EngineName::PromoCode.where(promo_code: promo_code))
errors.add :promo_code, "must be valid promo code"
return;
end
end
Does anyone has any idea how to achieve this? Please Help!
You have to make your activerecord model aware of the validation using the validate dsl statement. Does this work?
validate :ensure_valid_promo_code
def ensure_valid_promo_code
if promo_code.present? && (!promo_code.match(EngineName::PromoCode.promo_code))
errors.add :promo_code, "must be a valid promo code"
end
end
In case if someone is still looking for the solution, try this one -
def validate_promo_code
existing_code = EngineName::PromoCode.where(promo_code: promo_code)
if promo_code.present? and !(existing_code.present?)
errors.add :promo_code, "must be valid promo code"
end
end
This solution works for me.

Rails: How to enter value A in Model X only if value A exists in Model Y?

I'm trying to build a registration module where user can only register if their e-mail is already in an existing database.
Models:
User
OldUser
The condition on User will be
if OldUser.find_by_email(params[:UserName]) exists, allow user registration.
If not, then indicate error message.
This is really simple to do in PHP where I can just run a function to execute a mysql query. However, I couldn't figure out how to do it on Rails. It looks like I have to create a custom validator function but seems to be overkilled for a such simple condition.
It should be pretty simple to do. What have I missed?
Any pointer?
Edit 1:
This solution by dku.rajkumar works with a slight modification:
validate :check_email_existence
def check_email_existence
errors.add(:base, "Your email does not exist in our database") if OldUser.find_by_email(self.UserName).nil?
end
For cases like this, is it better to do validation in the model or at the controller?
you can do it as
if OldUser.find_by_email(params[:UserName])
User.create(params) // something like this i guess
else
flash[:error] = "Your email id does not exist in our database."
redirect_to appropriate_url
end
UPDATE: validation in model, so the validation will be done while calling User.create
class User < ActiveRecord::Base
validates :check_mail_id_presence
// other code
// other code
private
def check_mail_id_presence
errors.add("Your email id does not exist in our database.") if OldUser.find_by_email(self.UserName).nil?
end
end
I'd recommend starting with Devise.
See https://github.com/plataformatec/devise
Even if you have unusual needs like these, you can normally adapt it. Once you get to know it, it's extremely powerful, solid and debugged, and you can do all sorts of things with it.
Bellow is just an initial implementation .../app/controller/UsersController for User registration related actions.
def new
#user = User.new
end
def create
#user = User.new(params[:user])
#old_user = User.find_by_email(user.email)
if #old_user
if #user.save
# Handle successful save
else
render 'new' # and render some error message telling why registration was not succeed
end
else
# render some page with some sort of error message of 'new' new users
end
end
Update:
Check out the following resources for more info:
Ruby on Rails Tutorial
Rails: User/Password Authentication from Scratch, Part I/II

Rails 3, I need to save the current object and create another

I have
recommendations has_many approvals
Basically a recommendation gets created with an approval. The person who can approve it, comes in and checks an approve box, and needs to enter an email address for the next person who needs to approve (email is an attribute of an approval).
The caveat is that if the current_user has a user_type = SMT, then no more approvals are required. Thats the last approval.
I am using the recommendation/:id/approval/:id/edit action. I think I just need a Class method for the Approval. Something like:
before_save :save_and_create
def save_and_create
Some code that saves the current approval, creates a new one and asks me for the next admins email address, and send that user an email requesting that they approve
end
Any help would be greatly appreciated
# old post
class Recommendation << AR
validate :approval_completed?
def approval_completed?
if self.approvals.last.user.type == "SMT"
return true
else
return false # or a number for needed approvals: self.approvals.count >= 5
end
end
end
# new solution
class Approval << AR
validate :approvals_completed?
def approvals_completed?
if self.recommendation.approvals.last.user.type == "SMT"
return true
else
return false # or a number for needed approvals: self.approvals.count >= 5
end
end
end
I finally figured this one out. I simply created a before_save callback and the following method:
def create_next_approval
next_approval = self.recommendation.approvals.build(:email => self.next_approver_email, :user_id => User.find_by_email(next_approver_email))
next_approval.save if next_approver_email.present? && recently_approved?
end
hope it helps anyone else in my shoes.

How Rails: If a project has tasks it should not be deleted: how can I fix this?

Hi I have a project and each project has tasks. A task belongs to a project. Before I delete a project I want to check if there are related tasks. If there are tasks I don't want to delete the project. If there are no associated tasks, the project should be deleted. Can you please help me with the code? What am I missing?
class Project < ActiveRecord::Base
before_destroy :check_tasks
def check_tasks
if Project.find(params[:id]).tasks
flash[:notice] = 'This project has tasks.'
redirect_to :action => 'list_projects'
end
end
end
Return false from the before_destroy method to prevent the instance from being destroyed.
The method should also return a meaningful error for troubleshooting.
class Project < ActiveRecord::Base
before_destroy :check_tasks
def check_tasks
if self.tasks.any?
errors.add_to_base "Project has tasks and cannot be destroyed."
return false
end
end
end
Note: flash[:notice] and params[:attr_name] can only be used from controllers.
You have a couple of problems here.
You don't (or shouldn't) have access to the params variable (it's available in controllers and views only, unless you're passing it to the model, which is probably not what you want).
Your if checks against project.tasks which is an array - even an empty array evaluates to true, so your other code branch will never occur no matter if the project has tasks or not.
You should probably be setting error messages for the view from your ProjectsController#destroy action, not in your model.
Solutions:
Change Project.find(params[:id]) to self - you want to check the tasks for every instance of the Project.
Change the check in your if statement from if self.tasks to if self.tasks.any? which returns the value you want (false if the array is empty, true otherwise).
Move the flash[:notice] from your model to your controller, as well as the redirect_to call, where they belong. This means your check_tasks method can be changed to the following:
code:
def check_tasks
return !self.tasks.any?
end
Should the check be self instead? (not sure where you getting the params[:id] from).
Haven't checked this out yet though - but since I need something similar for my Users model I'll see how that works out and get back to you.
class Project < ActiveRecord::Base
before_destroy :check_tasks
private
def check_tasks
#edited
if tasks.empty?
false
end
end

Rails 3, help controlling access to a record based on the user id

I'm a Rails newbie.... Here's what I'm trying to do....
I created a scaffold for notes (t.text :content, t.integer :user_id)
What I want to do now is only allow user's to view notes that they created. ie (== user_id)
In my /app/controllers/notes_controller.rb
I have the following:
class NotesController < ApplicationController
before_filter :authenticate
before_filter :correct_user
.
.
.
.
def correct_user
#noteuserid = Note.find(:conditions=>["note.user_id=?", #noteuserid])
redirect_to(root_path) unless current_user?(#noteuserid)
end
I'm having problems understanding how to write the following line: #noteuserid = Note.find(:conditions=>["note.user_id=?", #noteuserid])
Any ideas?
Thanks
In Rails 3:
Note.where(:user_id=>current_user)
Or, you can start with the user...
User.find(current_user_id).notes.find(note_id)
So, firstly you want to find the Note being accessed by the user, then check whether that Note is valid for the user. I would try something like this (assuming that your current_user? method checks whether a given user id matches the current logged in user:
def correct_user
current_note = Note.find(params[:id])
redirect_to(root_path) unless current_user?(current_note.user_id)
end
Also, you may want to watch out for filtering all actions in the controller with your correct_user filter as actions to create a note may not have an id of a note to check against. Additionally, when you are viewing a collection of notes you will need to filter differently (e.g. Note.find(:all, :conditions => { :user_id => current_user_id })). It may be more appropriate to apply the correct logic in specific actions rather than as a generic filter.
Finally, you could look at the cancan plugin which would do a lot of the hard work for you with code like this.

Resources