Rails Raise Validation Error
Contents |
here for a quick overview of the site Help Center Detailed answers to any questions you might have Meta Discuss the workings and policies of this site About Us Learn rails raise validation exception more about Stack Overflow the company Business Learn more about hiring developers or rails exceptions posting ads with us Stack Overflow Questions Jobs Documentation Tags Users Badges Ask Question x Dismiss Join the Stack Overflow Community
Rails Raise Error
Stack Overflow is a community of 6.2 million programmers, just like you, helping each other. Join them; it only takes a minute: Sign up How can I add a validation error in before_save association
Activerecord::recordinvalid
callbacks up vote 7 down vote favorite I have two models: The Discount has and belongs to many Businsses. I want to validate that a Discount always have at least one business, together with another condition (for example active?). I tried the following: class Discount < ActiveRecord::Base has_and_belongs_to_many :businesses, before_remove: :validate_publish_status def validate_publish_status(*arg) if active? && businesses.count == 0 errors[:active] << 'discount with no business' end end end rails before_save validation However this does not work (no validation errors raised) and I realized that this is probably because it is only a callback, not a validation. How can I code it so I can use the errors like I do I custom validation? The controller action I have (for ajax): def remove @business = Business.find(params[:business_id]) if @business.in? @discount.businesses @discount.businesses.delete(@business) end render json: @business.as_json(only: [:id, :type, :name, :address], methods: [:city_name, :country_name]). merge(paths: paths_for(@discount, @business)) rescue ActiveRecord::RecordInvalid # even tried the generic Exception respond_to do |f| f.json { render json: {error: $!.message}, status: 403 } end end ruby-on-rails ruby-on-rails-3 share|improve this question edited Jan 31 '12 at 2:08 asked Jan 30 '12 at 9:12 lulalala 7,927765115 add a comment| 2 Answers 2 active oldest votes up vote 8 down vote accepted Could be your syntax on the before_remove callback or what's happening in the validation method itself. You also might want to add some debug code in the callback method to see if it's even making in there. *Note that the transaction will only be stopped if an exception is raised in the callback method. Since this is the case, you'll probably want to handle the exception logic in your controller to re-render the action:
helpers. A minimal implementation could be: class Person # Required dependency for ActiveModel::Errors extend ActiveModel::Naming def initialize @errors =
Rails Valid?
ActiveModel::Errors.new(self) end attr_accessor :name attr_reader :errors def validate! errors.add(:name, :blank, rails before_save return false message: "cannot be nil") if name.nil? end # The following methods are needed to be rails custom validation minimally implemented def read_attribute_for_validation(attr) send(attr) end def self.human_attribute_name(attr, options = {}) attr end def self.lookup_ancestors [self] end end The last three methods are required in http://stackoverflow.com/questions/9061569/how-can-i-add-a-validation-error-in-before-save-association-callbacks your object for Errors to be able to generate error messages correctly and also handle multiple languages. Of course, if you extend your object with ActiveModel::Translation you will not need to implement the last two. Likewise, using ActiveModel::Validations will handle the validation related methods for you. The above allows you http://api.rubyonrails.org/classes/ActiveModel/Errors.html to do: person = Person.new person.validate! # => ["cannot be nil"] person.errors.full_messages # => ["name cannot be nil"] # etc.. Methods # [], []= A add, add_on_blank, add_on_empty, added?, as_json B blank? C clear, count D delete E each, empty? F full_message, full_messages, full_messages_for G generate_message, get H has_key? I include? K key?, keys M marshal_dump, marshal_load N new S set, size T to_a, to_hash, to_xml V values Included Modules Enumerable Constants CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict] MESSAGE_OPTIONS = [:message] Attributes [R] details [R] messages Class Public methods new(base) Link Pass in the instance of the object that is using the errors object. class Person def initialize @errors = ActiveModel::Errors.new(self) end end Source: show | on GitHub # File activemodel/lib/active_model/errors.rb, line 72 def initialize(base) @base = base @messages = apply_default_array({}) @details = apply_default_array({}) end Instance Public methods [](attribute) Link When passed a symbol
creation date..." if created_on > Time.now end end ##News controller class Publish::NewsController < Publish::BaseController def create begin @news = News.new(params[:news]) rescue flash[:notice] https://www.sitepoint.com/community/t/rails-raising-model-exceptions-rescuing-in-controller/2661 = "Invalid creation date" render :action => 'new' end if @news.save flash[:notice] = 'News was successfully created.' redirect_to :action => 'list' else render :action => 'new' https://github.com/rails/rails/issues/13971 end end end ... I'm well off here, I know. When date validation fails I see a RuntimeError in the controller and the string specified in the rails raise News.validate_date method. Can someone explain how to properly deal with raising exceptions in the model and rescuing in the controller? Much appreciated... Luke_Redpath 2006-06-26 08:04:16 UTC #2 You're taking the right approach to rescuing exceptions however you are taking the wrong approach to your validations by using exceptions. Rails already has a built-in mechanism rails raise validation for dealing with whether or not a record is a valid so instead of raising an exception what you should be doing is adding your error to the errors array. This will make @yourobject.valid? and @yourobject.save return false. Theres also no need to set the validation method as a callback as Rails already has validation hooks you can tie into. So you should do something like this: class News < ActiveRecord::Base protected def validate self.errors.add(:created_on, "is invalid") if self.created_on > Time.now end end class Publish::NewsController < Publish::BaseController def create @news = News.new(params[:news]) if @news.save flash[:notice] = 'News was successfully created.' redirect_to :action => 'list' else flash[:error] = @news.errors render :action => 'new' end end end More information on Rails errors and validations: http://api.rubyonrails.org/classes/ActiveRecord/Errors.htmlhttp://api.rubyonrails.org/classes/ActiveRecord/Validations.html gregor002 2006-06-26 13:47:05 UTC #3 Cheers thanks for that, Luke. Mittineague 2014-09-19 01:36:01 UTC #4 Home Categories FAQ/Guidelines Terms of Service Privacy Policy Powered by Discourse, best viewed with JavaScript enabled Shop Versioning Reference Articles Premium
Sign in Pricing Blog Support Search GitHub This repository Watch 2,293 Star 33,153 Fork 13,503 rails/rails Code Issues 541 Pull requests 686 Projects 0 Pulse Graphs New issue ActiveRecord enum: use validation if exists instead of raising ArgumentError #13971 Closed tjschuck opened this Issue Feb 7, 2014 · 6 comments Labels activerecord enum Milestone No milestone Assignees No one assigned 7 participants tjschuck commented Feb 7, 2014 Regarding ActiveRecord::Enum, assume you had something like class Project < ActiveRecord::Base enum color: [:blue, :green, :red] validates :color, inclusion: { in: [:blue, :green, :red] } end Currently, if a "bad" value (say, "orange") is passed in, an ArgumentError is raised. It would be nice if the validation was preferred (with the ArgumentError as a fallback if there was no validation on that attribute) so that you'd be able to return a nicer error on the object later via the standard means: object.errors.messages # => {:color=>["is not included in the list"]} kind of thing 👍 6 rafaelfranca added this to the 4.1.0 milestone Feb 8, 2014 rafaelfranca added the activerecord label Feb 8, 2014 Ruby on Rails member rafaelfranca commented Feb 8, 2014 Not sure if we have a easy fix for this. To make validations work we will have to store the invalid value somewhere as string/symbol. Worth to check. rafaelfranca removed this from the 4.1.0 milestone Feb 8, 2014 Ruby on Rails member chancancode commented Feb 8, 2014 Hi @tjschuck, thanks for installing the beta and testing things early on – and most importantly providing feedback 💙 With what is being implemented right now, I feel that enum is not really a good fit for what you are trying to do. The current implementation is really just narrowly focused on ("optimized for" if you prefer) the use case suggested in the documentation – used by your application internally (to track internal "states"). For this purpose, I think raising an ArgumentError is the right/more helpful behaviour. I wouldn't go as far as saying that you shouldn't use enums for your use case (more generally, to expose user-facing attributes). However, if you do use it for that purpose, you'd have to fill in a lot of gaps manually at the moment – such as form helpers, translating the internal symbol/string to user facing labels, i18n, validations, etc. That might or might not change in the future. Personally, I'm not against expanding the focus to cover the second use case as well