Skip to content

Frequenly Asked Questions

Karel Pičman edited this page Dec 15, 2023 · 8 revisions

I receive many questions about how to access and manipulate the issue data, so I created standalone page, when I will answer to these questions.

How I can access and manipulate issue properties?

You can directly access next issue properties:

  • [RW] tracker_id
  • [RW] tracker -- Tracker object
  • [RW] project_id
  • [RW] project -- Project object
  • [RW] assigned_to_id
  • [RW] assigned_to -- Principal object
  • [RW] subject
  • [RW] description
  • [RW] due_date
  • [RW] category_id
  • [RW] category -- IssueCategory object
  • [RW] status_id
  • [RW] status -- IssueStatus object
  • [RW] priority_id
  • [RW] priority -- IssuePriority object
  • [RW] fixed_version_id
  • [RW] fixed_version -- Version object
  • [RW] author_id
  • [RW] author -- User object
  • [RW] created_on
  • [R ] updated_on
  • [RW] start_date
  • [RW] done_ratio
  • [RW] estimated_hours
  • [R ] parent -- Issue object
  • [RW] parent_issue_id
  • [RW] is_private

To access the property, use its name. To manipulate the property, use its name preceded by "self." and followed by "=". For example:

self.due_date = start_date.present? ? start_date+1.month : nil

Note that direct attributes assigning may cause security problems, if your script changes properties that should not be changed by the current user. For mass-assign issue attributes with security check, you can use safe_attributes=(attrs) method:

self.safe_attributes = {:status_id => 3, :subject => "..."}

How to know whether the issue property has been changed and what was its old value?

You can do this only in the before_save script, because after the issue was saved, it does not contain any changed properties anymore.

Most of the properties listed above (except object properties) has following forms:

  • tracker_id_changed? -- Returns true if tracker is changed
  • tracker_id_was -- Returns the old value of tracker_id

Also you can use:

  • changed? -- To know whether the issue has been changed
  • changes -- Returns array of all properties has been changed (containing the old and the new value)

Example:

 >> i = Issue.new
 >> i.changed?
 => true
 >> i.changes
 => {"priority_id"=>[0, 4], "status_id"=>[0, 1]}

(new issue is changed because Redmine initializes a priority and a status with default values)

How can I access and manipulate custom fields?

Here are some methods you can use for accessing and manipulating custom fields:

  • custom_field_value(custom_field_id) -- Returns a single custom value
  • custom_field_values -- Returns an array of CustomFieldValue objects. CustomFieldValue is a simple object that stores custom_field property and plain value property.
  • custom_field_values=(values) -- Sets the values of the object's custom fields, values is a hash like {'1' => 'foo', '2' => 'bar', custom_field_id => value}
  • custom_field_values_changed? -- Returns true if any of the custom values has been changed
  • custom_value_for(custom_field_id) -- Returns a CustomValue object for the specified custom field

How to know whether the issue custom field has been changed and what was its old value?

You can do this only in the before_save script.

You can call custom_field_value(custom_field_id) method to get a value that has not been yet saved. Against you can call custom_value_for(custom_field_id).try(&:value) to get an old custom field value. So compare both values to know whether custom field has been changed.

if custom_field_value(23) != custom_value_for(23).try(&:value)
   ...
end

How can I check whether current user has a role in project associated with workflow:

role_ids = User.current.membership(project).try(:role_ids) || []
if role_ids.include? 3
    ...
end

You can replace User.current.membership(project) with User.current.membership(<project_id>) where <project_id> is desired project's id instead of the current project.

How can I check whether current user is a member of a group?

if Group.find(3).users.include? User.current
    ...
end

What else methods of the Issue object I can use?

Here are some methods you can use:

  • visible?(usr=nil) -- Returns true if usr or current user is allowed to view the issue
  • copy(attributes=nil, copy_options={}) -- Returns an unsaved copy of the issue
  • copy? -- Returns true if the issue is a copy
  • new_record? -- Returns true if the issue is created, but not yet saved (use it only in +before_save+ script, because in +after_save+ it is always true)
  • closed? -- Returns true if the issue is closed, otherwise false
  • reopened? -- Returns true if the issue is being reopened
  • closing? -- Returns true if the issue is being closed
  • overdue? -- Returns true if the issue is overdue
  • behind_schedule? -- Is the amount of work done less than it should for the due date
  • children? -- Does this issue have children?
  • assignable_users -- Returns the list of users the issue can be assigned to
  • assignable_versions -- Versions that the issue can be assigned to
  • blocked? -- Returns true if this issue is blocked by another issue that is still open
  • new_statuses_allowed_to(user=User.current, include_default=false) -- Returns an array of statuses that user is able to apply
  • recipients -- Returns the mail adresses of users that should be notified
  • spent_hours -- Returns the number of hours spent on this issue
  • total_spent_hours -- Returns the total number of hours spent on this issue and its descendants
  • relations -- Returns all related issues
  • children -- Returns all children
  • duplicates -- Returns an array of issues that duplicate this one

How can I experiment with the issue interactively?

You can use Rails Console. Go to the Redmine directory and run:

ruby script\rails console production

for Redmine >= 2.0.0, or:

ruby script\console production

for Redmine < 2.0.0. It's ready to do some Ruby magic:

Loading production environment (Rails 2.3.14)
>> i = Issue.find(1)
=> #<Issue id: 1, tracker_id: 1, project_id: 1, subject: "test", description: "", due_date: nil, category_id: nil, status_id: 3, assigned_to_id: nil, 
priority_id: 4, fixed_version_id: nil, author_id: 2, lock_version: 4, created_on: "2012-08-28 16:10:39", updated_on: "2012-09-08 18:32:56", 
start_date: nil, done_ratio: 0, estimated_hours: nil, parent_id: nil, root_id: 1, lft: 1, rgt: 4, is_private: false>

>> i = Issue.new
=> #<Issue id: nil, tracker_id: 0, project_id: 0, subject: "", description: nil, due_date: nil, category_id: nil, status_id: 1, assigned_to_id: nil, 
priority_id: 4, fixed_version_id: nil, author_id: 0, lock_version: 0, created_on: nil, updated_on: nil, start_date: nil, 
done_ratio: 0, estimated_hours: nil, parent_id: nil, root_id: nil, lft: nil, rgt: nil, is_private: false>

Why I get error "Workflow script executable after saving the issue contains error: Validation failed" when trying to save the workflow.

The plugin creates a new issue (without parameters) and pass it to both scripts while validating. Thus it can validate a syntax of the code. If your script depends on it, for example, you create a issue based on "self" issue, this issue will be created on the validation and may not be saved due to failing saving some required fields.

Your script should contain some code checking whether it runs in a “validate” mode or it processing “real” issue. In most cases you can check whether issue is the new record (in the before_save script):

if self.new_record?

But if you need to process real new issues, you should consider using:

if self.subject.present?

Agreed, this is not obvious and leads to some dirty hacks in the script’s code, maybe I will change it somehow in the future.

How to send custom email from workflow?

Starting with version 0.1.2 there is ability to send custom emails (plain text/html/templated) straight from workflow.

Just call:

`Mailer.deliver_custom_email(User.current, text_body: 'Hello!')`

The mail being sent will use standard Redmine mail layout and headers. You can pass following parameters to Mailer#custom_email:

  • :text_body - plain text part of mail
  • :html_body - HTML part of mail
  • :template_name - you can specify template file used for rendering mail. For example, specify mailer/test_email to make Redmine looking for files mailer/test_email.html.erb and mailer/test_email.text.erb in your Redmine's app/views installation folder. You can also pass variables to templates with:
  • :template_params - Hash of instance variables to pass into template

You can pass also any other parameters, they will be used as mail headers.