各位同学对model中一坨坨的
validates_presence_of :name, :link
之类种种的代码不会觉得陌生。在执行save,update操作,rails会自动执行validation操作,并将错误信息存放在Model#errors中。通常,对于一般web程序来将,这就够了。我们可以将validation过程中的所有错误信息显示给用户,以进行修改。但是,在web api中,则没这么简单。一般来说,api通过xml返回结果,如果用户调用一个api的时候(比如通过调用api保存一个blog),如果这个时候validation出错了怎么办呢?如果只是简单的调用Model#errors#to_xml,返回给用户,那么其结果类似:
<errors>
<error>name can't be blank</error>
</errors>
当然,如果api用户只是发现有错误,将message简单显示,那没问题。如果客户端要针对错误进行更加灵活的操作应该怎么办呢(类似于我们在程序中自定义很多应用程序逻辑相关的Exception)?不可能针对每一个error的message来进行针对性处理,这个时候,我们就需要向error中添加和应用程序逻辑相关的error_code。rails并不支持该功能,那我们就只能挽起衣袖,自己动手。
首先,rails中关于model的validation,error。。。相关源代码请参见:activerecord-2.0.2\lib\activerecord\validation.rb。源代码不是很复杂,这里不详细阐述,只给出我目前找到的解决方案。
由于error这个东西在rails中的实现并不是十分OO(Model#errors是一个hash,rails将validation中出现的错误都塞到里面),因此我的办法颇费周折,可谓很暴力。正是由于errors是hash,不是一个一个error对象,因此,没办法很轻巧的增加一个error_code属性,我采用了增加另外一个hash:error_with_code来表示error信息和error_code信息。这样做的好处是不会影响原有的error逻辑。
class Errors
@@default_error_codes = {
:default => 101
}
def initialize(base) # :nodoc:
@base, @errors,@errors_with_code = base, {},{}
end
end
在Errors类中,我还定义了一个@@default_error_codes Hash,用来存放默认的error_codes,这样方便以后的扩展(先不详细讲述,先完成主干部分)。这里,你完全可以把@errors_with_code看成和@errors一样的东西,只不过,他多了一个error_code。那具体是怎么加入这个error_code的呢?我们继续
def add(attribute, msg = @@default_error_messages[:invalid],error_code = @@default_error_codes[:default])
@errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
@errors[attribute.to_s] << msg
@errors_with_code[attribute.to_s] = [] if @errors_with_code[attribute.to_s].nil?
@errors_with_code[attribute.to_s] << [ msg, error_code]
end
上面的add函数的前两行是rails的默认行为,他只是将error message存放在errors中,后面两行是我为rails增加的行为,将error_code和message封装成一个数组,存放在errors_with_code中。如果你查看rails validation的源代码,会发现,诸如validates_confirmation_of,validates_acceptance_of。。。之类我们熟悉的validation代码会调用这个add方法,为了使得可以自定义error_code,下面最最暴力的时候来了,在所有的validates_***_of的方法中,我们必须重写对add方法的调用,以将error_code塞进去,比如,针对validates_format_of方法,我们需要做如下重写:
def validates_format_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil }
configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp)
validates_each(attr_names, configuration) do |record, attr_name, value|
record.errors.add(attr_name, configuration[:message],configuration[:code]) unless value.to_s =~ configuration[:with]
end
end
请注意"configuration[:code]",这是和rails实现唯一不同的地方。有了他,我们在写validates_format_of的时候,就可以这样用:
validates_format_of :link, :with => /.../,:message => "error format of link",:code => 3001
这里的:code就是和应用程序相关error_code。至此,error_code的算是增加到了rails中。下面来看看我们怎么将结果(api返回错误信息的结果)返回。同样,这里,我不打算重写rails的默认to_xml行为,因为可能会影响其他程序的运作,所以,我在Error类中增加了一个to_xml_with_error_code方法:
def to_xml_with_error_code(options={})
options[:root] ||= "errors"
options[:indent] ||= 2
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
options[:builder].instruct! unless options.delete(:skip_instruct)
options[:builder].errors do |e|
full_messages_with_error_code.each { |msg,code| e.error(msg,"error_code" => code) }
end
end
和rails内部实现不同之处只是倒数第三行,我使用的是full_messages_with_error_code,而不是rails本身的full_messages,并且将error_code生成在了xml中("error_code" => code),下面是具体实现:
def full_messages_with_error_code # :nodoc:
full_messages = {}
@errors_with_code.each_key do |attr|
@errors_with_code[attr].each do |msg|
next if msg.nil?
msg = [ msg ].flatten
msg_text , msg_error_code = msg
if attr == "base"
full_messages[msg_text] = msg
else
full_messages[@base.class.human_attribute_name(attr) + " " + msg_text] = msg_error_code
end
end
end
return full_messages
end
rails内部的full_messages是一个数组,这里我使用的是一个Hash,为了方便message和error_code的对用。OK!修改工作完成!(不要忘了十分暴力的部分)下面来完成的看一下如何使用。
首先,在我们的Model中所有的validates_***_of 方法中增加:code => 2008之类的error_code,
validates_format_of :link, :with => /..../,:message => "error format of link",:code => 3001
如果validation过程中有错误,则调用:
model.errors.to_xml_with_error_code
将错误信息返回给客户,这样,客户端可以得到如下的错误结果:
<errors>
<error error_code="3001">Link error format of link</error>
</errors>
OK!现在客户端就可以针对error_code执行相应的逻辑处理!
2008.8.5 22:48 星期二
分享到:
- 2008-08-05 22:49
- 浏览 1993
- 评论(4)
- 论坛回复 / 浏览 (4 / 3663)
- 查看更多
相关推荐
《Rails Recipes with Source Code》是一本专注于Ruby on Rails框架实践技巧和源代码解析的书籍。Rails是基于Ruby语言的Web开发框架,以其“约定优于配置”(Convention over Configuration)的理念和“开发人员的...
本资料“RestFul_Rails_Dev_pdf_v_0.1.zip”包含了《RESTful Rails Development》的翻译版,将深入探讨如何在Rails中实现RESTful的设计模式。 首先,RESTful设计的核心概念是资源(Resources)。在Rails中,资源...
在您的config/initializers/rails_admin.rb初始化程序中添加配置: RailsAdmin . config do | config | config . model Post do list do sort_by :position # Add Default sorting sort_reverse false # sort p
在Ruby on Rails(Rails)框架中,为文件上传添加进度条功能可以显著提升用户体验,让用户在上传大文件时能够清楚地看到进度,增加交互性。本文将深入探讨如何在Rails应用中实现这一功能。 首先,我们需要理解文件...
这个插件名为`profanity_filter`,它是一个基于Ruby的库,可以集成到Rails应用中。`gem`是Ruby中的一个包管理器,用于安装、管理和分发代码库。通过在Rails项目中引入`profanity_filter` gem,你可以轻松地过滤掉...
通过研究这个示例,开发者可以掌握ActionCable的基本用法,了解如何在Rails5中实现WebSocket通信,以及如何将实时更新集成到现有的Rails应用程序中。此外,这个示例还展示了如何处理游戏状态的同步,这对于开发多人...
自述文件版本和设置$ ruby -vruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin18]$ rails -... $ rails new rails_model_test_hello_world -T -m ~/rtfb_template.rb$ cd rails_model_test_hello_world$ rail
这个 gem 是用于测量gem 的 Rails 集成。 它提供了 ActiveRecord 适配器,用于保存和检索测量值及其单位和模型验证。 用法 活动记录 列应具有_valueand_unit后缀,并且是DECIMALand VARCHAR,并且接受默认值。支持...
- **效果**:这将在应用中增加一个新的URL路径,指向指定控制器的动作。 #### 七、渲染视图 - **方法**:在控制器中使用`render`方法来显示特定的视图文件。 - **视图文件**:通常使用ERB模板语言来编写视图文件,...
在压缩包中的"authenticating_api_rails_devise-master"可能是一个Git仓库的名称,表明这个项目是用Git版本控制系统管理的,"master"分支通常代表开发的主要分支。这个目录可能包含以下文件和目录结构: - Gemfile...
Ruby_on_Rails_rails.zip Ruby_on_Rails_rails.zip Ruby_on_Rails_rails.zip Ruby_on_Rails_rails.zipRuby_on_Rails_rails.zip Ruby_on_Rails_rails.zip Ruby_on_Rails_rails.zip Ruby_on_Rails_rails.zipRuby_on_...
这是一个基于 Ruby on Rails 的应用程序,用于管理来自诸如 openSUSE Travel Support Program、GNOME 的 Conference Travel Subsidy Program 或 KDE eV Travel Cost Reimbursement 计划等自由软件组织的旅行帮助计划...
gem 'rails_fix_google_bot_accept' 然后执行: $ bundle 就是这样。 来源 gem 基于这个要点: : 它是由 Romain Champourlier 制作的,作为对这个问题的回答: ://stackoverflow....
标题 "rails_get_to_the_fest" 暗示着这是一个关于Ruby on Rails的项目,可能是为某种节日或活动创建的Web应用。Rails是基于Ruby语言的开源Web开发框架,它遵循MVC(模型-视图-控制器)架构模式,使得构建数据库驱动...
[Ruby_on_Rails][中文][Rails_5.x]__03-2_._安裝不同版本的Rails與產生Rails_5.x版
书中介绍了Ruby on Rails安装的最佳实践,以及如何通过Git、编辑器和Linux命令行等前置技能的学习,为后续的Rails开发打下基础。Git作为版本控制系统,对于团队协作开发项目尤为重要,学习它的使用方法能够帮助...
自述文件 该自述文件通常会记录启动和运行应用程序所需的所有步骤。 您可能要讲的内容: Ruby版本 系统依赖 配置 数据库创建 数据库初始化 如何运行测试套件 服务(作业队列,缓存服务器,搜索引擎等) ...
[Ruby_on_Rails][API][Rails_5.x]__01._Rails_與_Web_API_介紹
rails_apps_composer, 一个 gem,为 Rails 启动应用程序创建 Rails 应用程序模板 Rails 应用编辑器 Rails 应用程序编辑器 gem 安装一个 命令行 工具来从"食谱"的Collection 组装 Rails 应用程序。"你可以使用 rails_...