有没有办法覆盖ActiveRecord关联提供的方法之一?
比方说,我有以下典型的多态has_many:通过关联:
class Story < ActiveRecord::Base
has_many :taggings, :as => :taggable
has_many :tags, :through => :taggings, :order => :name
end
class Tag < ActiveRecord::Base
has_many :taggings, :dependent => :destroy
has_many :stories, :through => :taggings, :source => :taggable, :source_type => "Story"
end
Run Code Online (Sandbox Code Playgroud)
您可能知道这会为Story模型添加一大堆相关方法,如标签,标签<<,tags =,tags.empty?等.
我如何重写这些方法之一?特别是标签<<方法.覆盖普通的类方法很容易,但我似乎无法找到有关如何覆盖关联方法的任何信息.做点什么
def tags<< *new_tags
#do stuff
end
Run Code Online (Sandbox Code Playgroud)
调用它时会产生语法错误,所以显然不那么简单.
在我详细介绍之前,我会明确指出:有没有人想出办法让Carrierwave保存文件,其名称为时间戳或每个文件唯一的任意字符串?
默认情况下,Carrierwave将每个文件及其备用版本保存在其自己的目录中(以型号ID号命名).我不是这个的粉丝,因为为了使用大的圆形数字而不是一个1000的目录,文件(在我的情况下是图片)中我们得到一个目录,其中有1,000个子目录,每个子目录有一个或两个文件.呸.
现在,当您覆盖Uploader的store_dir方法时,如下所示:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}"
end
Run Code Online (Sandbox Code Playgroud)
你最终得到了我想要的确切行为.所有文件(图片)都进入一个大的快乐文件夹.当对象被删除时,不再有子文件夹.
只有一个问题.文件冲突.如果你上传delicious_cake.jpg两次,那么即使它们是美味蛋糕的两张不同的照片,它也会覆盖第一个!这显然是为什么该store_dir方法/#{model.id}在它返回的值的末尾有额外的限制.
那么该怎么办?在阅读了一下后,我发现在生成的上传器文件中有一个明显的解决方案被注释掉了.
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
Run Code Online (Sandbox Code Playgroud)
经过一番搜索,我发现有人做了以下事情
def filename
@name ||= "#{secure_token}.#{file.extension}" if original_filename
end
Run Code Online (Sandbox Code Playgroud)
这让我思考,为什么不这样做呢
def filename
@name ||= "#{(Time.now.to_i.to_s + Time.now.usec.to_s).ljust(16, '0')}#{File.extname(original_filename)}"
end
Run Code Online (Sandbox Code Playgroud)
事情变得非常糟糕.这个问题filename显然是为文件的每个版本调用,所以我们最终得到文件名,如1312335603175322.jpg和thumb_1312335603195323.jpg.请注意细微差别?每个文件名都基于filename为该特定版本调用的时间.那根本不会做.
我接下来厌倦了使用model.created_at时间戳的基础.只有一个问题,即第一个版本返回nil,因为它还没有放入数据库.
经过一番思考后,我决定在我的照片控制器中尝试以下操作.
def create
if params[:picture] and params[:picture][:image]
params[:picture][:image].original_filename = …Run Code Online (Sandbox Code Playgroud) 我已经和Rails一起工作了一段时间,我发现自己经常做的一件事就是在显示之前检查我的视图代码中是否有某些属性或对象为nil.我开始怀疑这是否总是最好的主意.
到目前为止,我的理由是,由于我的应用程序依赖于用户输入,因此可能会发生意外情况.如果我从编程中学到一件事,那就是用户输入程序员没想到的东西是运行时错误的最大来源之一.通过检查零值,我希望回避这一点并让我的观点优雅地处理问题.
虽然我通常由于各种原因在我的模型或控制器代码中有类似的无效或无效的值检查.我不会在最严格的意义上称它为代码重复,但它似乎并不是很干.如果我已经在我的控制器中检查了nil对象,那么我的视图是否只是假设对象真的不是零?对于可以显示为零的属性,每次检查都是有意义的,但对于对象本身,我不确定什么是最佳实践.
这是我所说的简化但典型的例子:
控制器代码
def show
@item = Item.find_by_id(params[:id])
@folders = Folder.find(:all, :order => 'display_order')
if @item == nil or @item.folder == nil
redirect_to(root_url) and return
end
end
Run Code Online (Sandbox Code Playgroud)
查看代码
<% if @item != nil %>
display the item's attributes here
<% if @item.folder != nil %>
<%= link_to @item.folder.name, folder_path(@item.folder) %>
<% end %>
<% else %>
Oops! Looks like something went horribly wrong!
<% end %>
Run Code Online (Sandbox Code Playgroud)
这是个好主意还是只是愚蠢?
我想知道写这样的函数是好还是坏.
def test(x)
if x == 1
return true
else
return "Error: x is not equal to one."
end
end
Run Code Online (Sandbox Code Playgroud)
然后使用它我们做这样的事情:
result = test(1)
if result != true
puts result
end
result = test(2)
if result != true
puts result
end
Run Code Online (Sandbox Code Playgroud)
这只显示第二次测试调用的错误消息.
我正在考虑这样做,因为在一个rails项目中,我正在我的控制器代码中工作,我调用模型的实例方法,如果出现问题,我希望模型将错误消息返回给控制器,控制器接受错误消息并将其放入闪存并重定向.有点像这样
def create
@item = Item.new(params[:item])
if !@item.nil?
result = @item.save_image(params[:attachment][:file])
if result != true
flash[:notice] = result
redirect_to(new_item_url) and return
end
#and so on...
Run Code Online (Sandbox Code Playgroud)
这样我就不会在控制器中构造错误消息,只是将它们传递给它们,因为我真的不希望控制器关注save_image方法本身做了什么,只是它是否有效.
这对我来说很有意义,但我很好奇这是否被认为是写作方法的好或坏方式.请记住,我在最常见的意义上问这个主要涉及ruby,只是碰巧我在rails项目中这样做,控制器的实际逻辑真的不是我关心的问题.
我无法在这里或其他任何地方找到限制资源路由和在Rails 3中添加其他非RESTful路由的任何内容.这可能非常简单,但我遇到的每个示例或解释只针对一个案例而不是两者都在同一时间.
这是我在Rails 2中所做的一个例子:
map.resources :sessions, :only => [:new, :create, :destroy], :member => {:recovery => :get}
非常简单,我们只需要7个RESTful路由中的3个,因为其他路由对此资源没有任何意义,但我们还想添加另一个用于帐户恢复的路由.
现在从我收集的内容来看,这些事情中的任何一个都非常简单:
resources :sessions, :only => [:new, :create, :destroy]
就像在Rails 2中一样.并且:
resources :sessions do
member do
get :recovery
end
end
Run Code Online (Sandbox Code Playgroud)
那么,我如何将这两者结合起来呢?我还可以使用旧的Rails 2方式吗?在Rails 3中有一种首选的方法吗?
这将是一个非常愚蠢的问题,我只是知道它,但不管怎样我会问,因为它让我发疯.
我如何使作为标签的行为起作用?
我把它作为一个宝石安装,gem install acts-as-taggable-on因为我似乎无法安装插件工作,但这是另外一批可能真的很愚蠢的问题.无论如何,没有问题,它安装正确.
我没有ruby script/generate acts_as_taggable_on_migration和rake db:migrate,再没有任何问题.
我添加acts_as_taggable到模型中我想使用标签,启动服务器然后加载模型的索引只是为了看看我到目前为止是否正在工作并得到以下错误:未定义的局部变量或方法`acts_as_taggable '为#.
我认为这只意味着我需要对require 'acts-as-taggable-on'我的模型文件做一些事情,因为这通常是宝石所必需的.所以我做了那个点击刷新并得到了uninitialized constant ActiveRecord::VERSION.我甚至不会假装开始知道这意味着什么出错了.
我在某处或其他地方出错了我需要做的事情.在我看来,安装说明就像他们只是假设你一般都知道自己在做什么,甚至没有开始解释当出现问题时该怎么做.
ruby rubygems ruby-on-rails ruby-on-rails-plugins acts-as-taggable-on
大约一年前,我决定确保每个具有非唯一文本的flash通知都会从模块中的方法获取文本.我这样做的最初原因是为了避免反复输入相同的字符串.如果我想改变措辞,我可以在一个地方轻松地做到这一点,并且错综复杂地反复重复相同事情的可能性会降低.
我最终得到的是:
module Messages
def format_error_messages(errors)
errors.map {|attribute, message| "Error: #{attribute.to_s.titleize} #{message}.<br />"}
end
def error_message_could_not_find(object_name)
"Error: Unable to find the specified " + object_name + "!"
end
def error_message_could_not_create(object_name)
"Error: Unable to create the " + object_name + "!"
end
def error_message_could_not_save(object_name)
"Error: Unable to save " + object_name + " to database!"
end
def error_message_could_not_update(object_name)
"Error: Unable to update " + object_name + "!"
end
def error_message_could_not_destory(object_name)
"Error: Unable to destroy " + object_name + "!"
end
def …Run Code Online (Sandbox Code Playgroud) 所以我发现自己需要<br />在我正在处理的项目中从字符串的开头和结尾删除标签.我做了一个快速的小方法来完成我需要做的事情,但我不相信这是做这类事情的最好方法.我怀疑可能有一个方便的正则表达式,我可以用它来做几行.这是我得到的:
def remove_breaks(text)
if text != nil and text != ""
text.strip!
index = text.rindex("<br />")
while index != nil and index == text.length - 6
text = text[0, text.length - 6]
text.strip!
index = text.rindex("<br />")
end
text.strip!
index = text.index("<br />")
while index != nil and index == 0
text = test[6, text.length]
text.strip!
index = text.index("<br />")
end
end
return text
end
Run Code Online (Sandbox Code Playgroud)
现在"<br />"可能真的是任何东西,并且制作一个通用的函数可能更有用,该函数将需要从开头和结尾剥离的字符串作为参数.
我对如何使这个更清洁的任何建议持开放态度,因为这似乎可以改进.
ruby ×7
activerecord ×1
carrierwave ×1
filenames ×1
overriding ×1
refactoring ×1
routes ×1
rubygems ×1
string ×1