Project

General

Profile

Patch #2696 ยป add_subcategory_to_categories.diff

svn diff patch for 2399 to issue_subcategories - Rob Elsner, 2009-02-07 23:40

View differences:

test/unit/issue_subcategory_test.rb (revision 0)
1
require 'test_helper'
2

  
3
class IssueCategorySubcategoryTest < ActiveSupport::TestCase
4
  fixtures :issue_subcategories, :issues
5

  
6
  def setup
7
    @subcategory = IssueSubcategory.find(1)
8
  end
9

  
10
  def test_destroy
11
    issue = @subcategory.issues.first
12
    @subcategory.destroy
13
    # Make sure the category was nullified on the issue
14
    assert_nil issue.reload.subcategory
15
  end
16

  
17
  def test_destroy_with_reassign
18
    issue = @subcategory.issues.first
19
    reassign_to = IssueSubcategory.find(2)
20
    @subcategory.destroy(reassign_to)
21
    # Make sure the issue was reassigned
22
    assert_equal reassign_to, issue.reload.subcategory
23
  end
24
end
test/fixtures/issue_subcategories.yml (revision 0)
1
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2

  
3
one:
4
  issue_category_id: 1
5
  name: Toner
6

  
7
two:
8
  issue_category_id: 1
9
  name: Paper
app/helpers/issue_categories_helper.rb (working copy)
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18 18
module IssueCategoriesHelper
19
  def add_issue_subcategory_link(name)
20
     link_to_function name do |page|
21
      page.insert_html :bottom, :issue_subcategories, :partial => "subcategories", :object => IssueSubcategory.new
22
    end
23
  end
19 24
end
app/helpers/issues_helper.rb (working copy)
80 80
      when 'category_id'
81 81
        c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value
82 82
        c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
83
      when 'subcategory_id'
84
        c = IssueSubcategory.find_by_id(detail.value) and value = c.name if detail.value
85
        c = IssueSubcategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
83 86
      when 'fixed_version_id'
84 87
        v = Version.find_by_id(detail.value) and value = v.name if detail.value
85 88
        v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value
......
150 153
                  l(:field_subject),
151 154
                  l(:field_assigned_to),
152 155
                  l(:field_category),
156
                  l(:field_sub_category),
153 157
                  l(:field_fixed_version),
154 158
                  l(:field_author),
155 159
                  l(:field_start_date),
......
176 180
                  issue.subject,
177 181
                  issue.assigned_to,
178 182
                  issue.category,
183
                  issue.subcategory,
179 184
                  issue.fixed_version,
180 185
                  issue.author.name,
181 186
                  format_date(issue.start_date),
app/models/issue_category.rb (working copy)
18 18
class IssueCategory < ActiveRecord::Base
19 19
  belongs_to :project
20 20
  belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
21
  has_many :subcategories, :class_name => 'IssueSubcategory', :foreign_key => 'category_id', :dependent => :nullify
21 22
  has_many :issues, :foreign_key => 'category_id', :dependent => :nullify
22 23
  
23 24
  validates_presence_of :name
24 25
  validates_uniqueness_of :name, :scope => [:project_id]
25 26
  validates_length_of :name, :maximum => 30
27

  
28
  # after something changes, we need to save the changes!
29
  after_update :save_sub_categories
26 30
  
27 31
  alias :destroy_without_reassign :destroy
28 32
  
......
34 38
    end
35 39
    destroy_without_reassign
36 40
  end
37
  
41

  
42
  # we get passed a hash of key => value pairs that describe
43
  # the new subcategories.  we need to set their ID to this
44
  # objects ID
45
  def new_issue_subcategories=(subcategory_elements)
46
    subcategory_elements.each do |subcat|
47
      subcat[:category_id] = :id
48
      subcategories.build(subcat)
49
    end
50
  end
51

  
52
  # update or delete existing address lines
53
  def existing_issue_subcategories=(subcategory_elements)
54
    subcategories.reject(&:new_record?).each do |line|
55
      attributes = subcategory_elements[line.id.to_s]
56
      if attributes
57
        line.attributes = attributes
58
      else
59
        subcategories.delete(line)
60
      end
61
    end
62
  end
63

  
38 64
  def <=>(category)
39 65
    name <=> category.name
40 66
  end
41 67
  
42 68
  def to_s; name end
69

  
70
  protected
71
  #called after a change (add/update/delete) to save to the database
72
  def save_sub_categories
73
    subcategories.each do |subcategory|
74
      subcategory.save(false)
75
    end
76
  end
43 77
end
app/models/issue.rb (working copy)
24 24
  belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
25 25
  belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
26 26
  belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
27
  belongs_to :subcategory, :class_name => 'IssueSubcategory', :foreign_key => 'subcategory_id'
27 28

  
28 29
  has_many :journals, :as => :journalized, :dependent => :destroy
29 30
  has_many :time_entries, :dependent => :delete_all
app/models/issue_subcategory.rb (revision 0)
1
class IssueSubcategory < ActiveRecord::Base
2
  belongs_to :issue_category, :foreign_key => 'category_id'
3
  validates_presence_of :name
4
  validates_uniqueness_of :name, :scope => [:category_id]
5
  validates_length_of :name, :maximum => 30
6

  
7
  def <=>(subcategory)
8
    name <=> subcategory.name
9
  end
10

  
11
  def to_s; name end
12
end
app/controllers/issues_controller.rb (working copy)
21 21
  before_filter :find_issue, :only => [:show, :edit, :reply]
22 22
  before_filter :find_issues, :only => [:bulk_edit, :move, :destroy]
23 23
  before_filter :find_project, :only => [:new, :update_form, :preview]
24
  before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu]
24
  before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu, :update_issue_subcategories]
25 25
  before_filter :find_optional_project, :only => [:index, :changes, :gantt, :calendar]
26 26
  accept_key_auth :index, :changes
27 27

  
......
43 43
  helper :timelog
44 44
  include Redmine::Export::PDF
45 45

  
46
  def update_issue_subcategories
47
    results = IssueSubcategory.find(:all, :conditions=>{"category_id"=> params[:category_id]})
48
    render :update do |page|
49
      page.replace_html 'issue_subcategory', :partial => 'subcategories', :object => results
50
    end
51

  
52
  end
53

  
46 54
  def index
47 55
    retrieve_query
48 56
    sort_init 'id', 'desc'
app/views/issue_categories/_subcategories.rhtml (revision 0)
1
<span class="issue_subcategory">
2
<% new_or_existing = subcategories.new_record? ? 'new' : 'existing' %>
3
<% prefix = "category[#{new_or_existing}_issue_subcategories][]" %>
4
<% fields_for prefix, subcategories do |subcategory_form| -%>
5
<p>
6
<%= subcategory_form.text_field :name %>
7
<%= link_to_function l(:button_delete) , "$(this).up('.issue_subcategory').remove()" %>
8
</p>
9
<% end %>
10
</span>
app/views/issue_categories/_form.rhtml (working copy)
3 3
<div class="box">
4 4
<p><%= f.text_field :name, :size => 30, :required => true %></p>
5 5
<p><%= f.select :assigned_to_id, @project.users.collect{|u| [u.name, u.id]}, :include_blank => true %></p>
6
<p>
7
<%= add_issue_subcategory_link l(:label_issue_subcategory_new) %>
8
<div id="issue_subcategories">
9
<%= render :partial => 'subcategories', :collection => @category.subcategories %>
6 10
</div>
11

  
12
</p>
13

  
14
</div>
app/views/issues/_subcategories.rhtml (revision 0)
1
<%= subcategories.nil? ? "" : collection_select(:issue, :subcategory_id, subcategories, :id, :name,:include_blank=>true) %>
app/views/issues/_form.rhtml (working copy)
1 1
<% if @issue.new_record? %>
2 2
<p><%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
3 3
<%= observe_field :issue_tracker_id, :url => { :action => :new },
4
                                     :update => :content,
5
                                     :with => "Form.serialize('issue-form')" %>
4
:update => :content,
5
:with => "Form.serialize('issue-form')" %>
6 6
<hr />
7 7
<% end %>
8 8

  
......
26 26
<p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %></p>
27 27
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
28 28
<% unless @project.issue_categories.empty? %>
29
<p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
30
<%= prompt_to_remote(l(:label_issue_category_new),
31
                     l(:label_issue_category_new), 'category[name]', 
32
                     {:controller => 'projects', :action => 'add_issue_category', :id => @project},
33
                     :class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %></p>
29
<p>
30
    <%= f.select(:category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), {:include_blank => true}, {:onchange => "#{remote_function(:url  => {:action => "update_issue_subcategories"},
31
                               :with => "'category_id='+value")}"} )%>
32
<span id="issue_subcategory">
33
<% unless @issue.category.nil? %>
34
<%=  f.collection_select(:subcategory_id, @issue.category.subcategories, :id, :name,:include_blank=>true) %>
34 35
<% end %>
35
<%= content_tag('p', f.select(:fixed_version_id, 
36
                              (@project.versions.sort.collect {|v| [v.name, v.id]}),
37
                              { :include_blank => true })) unless @project.versions.empty? %>
36
</span>
37
    <%= prompt_to_remote(l(:label_issue_category_new),
38
l(:label_issue_category_new), 'category[name]',
39
{:controller => 'projects', :action => 'add_issue_category', :id => @project},
40
:class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %>
41
</p>
42
<% end %>
43
<%= content_tag('p', f.select(:fixed_version_id,
44
(@project.versions.sort.collect {|v| [v.name, v.id]}),
45
{ :include_blank => true })) unless @project.versions.empty? %>
38 46
</div>
39 47

  
40 48
<div class="splitcontentright">
app/views/issues/show.rhtml (working copy)
31 31
    <td class="progress"><b><%=l(:field_done_ratio)%>:</b></td><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
32 32
</tr>
33 33
<tr>
34
    <td class="category"><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
34
    <td class="category"><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %>
35
    <%=h @issue.subcategory ? " / "+@issue.subcategory.name : "-" %></td>
35 36
    <% if User.current.allowed_to?(:view_time_entries, @project) %>
36 37
    <td class="spent-time"><b><%=l(:label_spent_time)%>:</b></td>
37 38
    <td class="spent-hours"><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %></td>
lang/en.yml (working copy)
122 122
field_max_length: Maximum length
123 123
field_value: Value
124 124
field_category: Category
125
field_subcategory: Subcategory
125 126
field_title: Title
126 127
field_project: Project
127 128
field_issue: Issue
......
321 322
label_issue_status_plural: Issue statuses
322 323
label_issue_status_new: New status
323 324
label_issue_category: Issue category
325
label_issue_subcategory: Issue subcategory
324 326
label_issue_category_plural: Issue categories
327
label_issue_subcategory_plural: Issue subcategories
325 328
label_issue_category_new: New category
329
label_issue_subcategory_new: New subcategory
326 330
label_custom_field: Custom field
327 331
label_custom_field_plural: Custom fields
328 332
label_custom_field_new: New custom field
db/migrate/20090125190215_create_issue_category_subcategories.rb (revision 0)
1
  class CreateIssueCategorySubcategories < ActiveRecord::Migration
2
  def self.up
3
    create_table :issue_subcategories do |t|
4
      t.integer :category_id
5
      t.string :name,  :limit => 30, :null => false
6
      t.timestamps
7
    end
8
  end
9

  
10
  def self.down
11
    drop_table :issue_subcategories
12
  end
13
end
db/migrate/20090125191829_add_sub_categories_to_issues.rb (revision 0)
1
class AddSubCategoriesToIssues < ActiveRecord::Migration
2
  def self.up
3
	add_column :issues, :subcategory_id, :integer
4
  end
5

  
6
  def self.down
7
	remove_column :issues, :subcategory_id
8
  end
9
end
    (1-1/1)