开发者

Validation problem with a Redmine hook

I am having a validation problem when writing a Redmine plugin.

I'm writing a hook for the issue model, and as a part of the hook method, i would like to invalidate the creation of the issue, by adding a custom error:

  def controller_issues_new_before_save( context = { } )
     context[:issue].errors.add(:due_date, "A custom error")
  end

For testing purposes, I have written a patch that overwrites Issue.validate_on_create, but it seems that every time when entering validate_on_create errors.count is set to zero.

I need to stop the creation of the issue object , but only when an attribute is set into another model obje开发者_如何转开发ct.

I thought about writing this in the validate_on_create method, but then I would need to pass it the other object.

The first solution that I thought about would be to insert an additional field in the Issue model, and modify it inside the hook.

Something like :

  def controller_issues_new_before_save( context = { } )
    context[:issue].can_validate = false
  end

  def validate_on_create
    unless can_validate 
      errors.add("error", "A custom error")
    end
  end   

where Issue.can_validate is an addition to the Issue model

However, this does not seem the best approach here. Is there an easier way?


If you are wanting to validate data you should patch the models directly and not use hooks. Hooks are meant to be used to insert HTML onto a page or change the control flow of a controller. Using hooks also means that your code will only work for that one path through the application, so if someone creates an issue somewhere else then you code will not run.

To create a patch you just need to do two things:

  1. Create a module that has your code
  2. Make Redmine include that module in it's Issue class

I've done this exact thing in a plugin that adds a validation on an Issue to require that due dates are set in the future. The patch for it is rather simple so I'll include it here:

module RedmineRequireIssueDueDateInFuture
  module Patches
    module IssuePatch
      def self.included(base)
        base.class_eval do
          unloadable

          validate :due_date_in_future

          protected
          def due_date_in_future
            return true if due_date.nil?

            if due_date.to_time < Date.today.beginning_of_day
              errors.add :due_date, :not_in_future
            end

          end

        end
      end
    end
  end
end

Inside of the class_eval is where you would put your own code, I'd recommend using a different name than validate_on_create. Otherwise you might have problems with other code if they want to use that method too.

The second part (including the module into Redmine) is rather easy. Just require the Issue class and use include to add it to the class.

# init.rb
require 'dispatcher'
Dispatcher.to_prepare :redmine_require_issue_due_date_in_future do
  require_dependency 'issue'
  Issue.send(:include, RedmineRequireIssueDueDateInFuture::Patches::IssuePatch)
end

You need to wrap this in the Dispatcher to keep things working in development mode. I've written about it on my blog.

Feel free to copy my plugin from github to make your changes, it's pretty simple. https://github.com/edavis10/redmine_require_issue_due_date_in_future


Since Redmine 2.0, you should replace the code in init.rb by this in Eric Davis response :

#init.rb
ActionDispatch::Callbacks.to_prepare do 
  require_dependency 'issue'
  Issue.send(:include, RedmineRequireIssueDueDateInFuture::Patches::IssuePatch)
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜