Resourcified custom fields.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@8144 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
877fbc15da
commit
b127f9157d
|
@ -19,6 +19,8 @@ class CustomFieldsController < ApplicationController
|
||||||
layout 'admin'
|
layout 'admin'
|
||||||
|
|
||||||
before_filter :require_admin
|
before_filter :require_admin
|
||||||
|
before_filter :build_new_custom_field, :only => [:new, :create]
|
||||||
|
before_filter :find_custom_field, :only => [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name }
|
@custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name }
|
||||||
|
@ -26,39 +28,51 @@ class CustomFieldsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@custom_field = begin
|
end
|
||||||
if params[:type].to_s.match(/.+CustomField$/)
|
|
||||||
params[:type].to_s.constantize.new(params[:custom_field])
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
end
|
|
||||||
(redirect_to(:action => 'index'); return) unless @custom_field.is_a?(CustomField)
|
|
||||||
|
|
||||||
|
def create
|
||||||
if request.post? and @custom_field.save
|
if request.post? and @custom_field.save
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field)
|
call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field)
|
||||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
redirect_to :action => 'index', :tab => @custom_field.class.name
|
||||||
else
|
else
|
||||||
@trackers = Tracker.find(:all, :order => 'position')
|
render :action => 'new'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@custom_field = CustomField.find(params[:id])
|
end
|
||||||
if request.post? and @custom_field.update_attributes(params[:custom_field])
|
|
||||||
|
def update
|
||||||
|
if request.put? and @custom_field.update_attributes(params[:custom_field])
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
|
call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
|
||||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
redirect_to :action => 'index', :tab => @custom_field.class.name
|
||||||
else
|
else
|
||||||
@trackers = Tracker.find(:all, :order => 'position')
|
render :action => 'edit'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@custom_field = CustomField.find(params[:id]).destroy
|
@custom_field.destroy
|
||||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
redirect_to :action => 'index', :tab => @custom_field.class.name
|
||||||
rescue
|
rescue
|
||||||
flash[:error] = l(:error_can_not_delete_custom_field)
|
flash[:error] = l(:error_can_not_delete_custom_field)
|
||||||
redirect_to :action => 'index'
|
redirect_to :action => 'index'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def build_new_custom_field
|
||||||
|
@custom_field = CustomField.new_subclass_instance(params[:type], params[:custom_field])
|
||||||
|
if @custom_field.nil?
|
||||||
|
render_404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_custom_field
|
||||||
|
@custom_field = CustomField.find(params[:id])
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_404
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -155,6 +155,22 @@ class CustomField < ActiveRecord::Base
|
||||||
find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
|
find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns an instance of the given subclass name
|
||||||
|
def self.new_subclass_instance(class_name, *args)
|
||||||
|
klass = nil
|
||||||
|
begin
|
||||||
|
klass = class_name.to_s.classify.constantize
|
||||||
|
rescue
|
||||||
|
# invalid class name
|
||||||
|
end
|
||||||
|
unless subclasses.include? klass
|
||||||
|
klass = nil
|
||||||
|
end
|
||||||
|
if klass
|
||||||
|
klass.new(*args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def type_name
|
def type_name
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -81,7 +81,7 @@ function toggle_custom_field_format() {
|
||||||
when "IssueCustomField" %>
|
when "IssueCustomField" %>
|
||||||
|
|
||||||
<fieldset><legend><%=l(:label_tracker_plural)%></legend>
|
<fieldset><legend><%=l(:label_tracker_plural)%></legend>
|
||||||
<% for tracker in @trackers %>
|
<% Tracker.all.each do |tracker| %>
|
||||||
<%= check_box_tag "custom_field[tracker_ids][]",
|
<%= check_box_tag "custom_field[tracker_ids][]",
|
||||||
tracker.id,
|
tracker.id,
|
||||||
(@custom_field.trackers.include? tracker),
|
(@custom_field.trackers.include? tracker),
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%>
|
<% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%>
|
||||||
<tr class="<%= cycle("odd", "even") %>">
|
<tr class="<%= cycle("odd", "even") %>">
|
||||||
<td><%= link_to h(custom_field.name), :action => 'edit', :id => custom_field %></td>
|
<td><%= link_to h(custom_field.name), edit_custom_field_path(custom_field) %></td>
|
||||||
<td align="center"><%= l(Redmine::CustomFieldFormat.label_for(custom_field.field_format)) %></td>
|
<td align="center"><%= l(Redmine::CustomFieldFormat.label_for(custom_field.field_format)) %></td>
|
||||||
<td align="center"><%= checked_image custom_field.is_required? %></td>
|
<td align="center"><%= checked_image custom_field.is_required? %></td>
|
||||||
<% if tab[:name] == 'IssueCustomField' %>
|
<% if tab[:name] == 'IssueCustomField' %>
|
||||||
|
@ -22,8 +22,8 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<td align="center" style="width:15%;"><%= reorder_links('custom_field', {:action => 'edit', :id => custom_field}) %></td>
|
<td align="center" style="width:15%;"><%= reorder_links('custom_field', {:action => 'edit', :id => custom_field}) %></td>
|
||||||
<td class="buttons">
|
<td class="buttons">
|
||||||
<%= link_to(l(:button_delete), { :action => 'destroy', :id => custom_field },
|
<%= link_to(l(:button_delete), custom_field_path(custom_field),
|
||||||
:method => :post,
|
:method => :delete,
|
||||||
:confirm => l(:text_are_you_sure),
|
:confirm => l(:text_are_you_sure),
|
||||||
:class => 'icon icon-del') %>
|
:class => 'icon icon-del') %>
|
||||||
</td>
|
</td>
|
||||||
|
@ -32,4 +32,4 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<p><%= link_to l(:label_custom_field_new), {:action => 'new', :type => tab[:name]}, :class => 'icon icon-add' %></p>
|
<p><%= link_to l(:label_custom_field_new), new_custom_field_path(:type => tab[:name]), :class => 'icon icon-add' %></p>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
» <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
|
» <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
|
||||||
» <%=h @custom_field.name %></h2>
|
» <%=h @custom_field.name %></h2>
|
||||||
|
|
||||||
<% labelled_form_for :custom_field, @custom_field, :url => { :action => "edit", :id => @custom_field } do |f| %>
|
<% labelled_form_for :custom_field, @custom_field, :url => custom_field_path(@custom_field), :html => {:method => :put} do |f| %>
|
||||||
<%= render :partial => 'form', :locals => { :f => f } %>
|
<%= render :partial => 'form', :locals => { :f => f } %>
|
||||||
<%= submit_tag l(:button_save) %>
|
<%= submit_tag l(:button_save) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
» <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
|
» <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %>
|
||||||
» <%= l(:label_custom_field_new) %></h2>
|
» <%= l(:label_custom_field_new) %></h2>
|
||||||
|
|
||||||
<% labelled_form_for :custom_field, @custom_field, :url => { :action => "new" } do |f| %>
|
<% labelled_form_for :custom_field, @custom_field, :url => custom_fields_path do |f| %>
|
||||||
<%= render :partial => 'form', :locals => { :f => f } %>
|
<%= render :partial => 'form', :locals => { :f => f } %>
|
||||||
<%= hidden_field_tag 'type', @custom_field.type %>
|
<%= hidden_field_tag 'type', @custom_field.type %>
|
||||||
<%= submit_tag l(:button_save) %>
|
<%= submit_tag l(:button_save) %>
|
||||||
|
|
|
@ -184,6 +184,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||||
|
|
||||||
map.resources :trackers, :except => :show
|
map.resources :trackers, :except => :show
|
||||||
map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
|
map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
|
||||||
|
map.resources :custom_fields, :except => :show
|
||||||
|
|
||||||
#left old routes at the bottom for backwards compat
|
#left old routes at the bottom for backwards compat
|
||||||
map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
|
map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
|
||||||
|
|
|
@ -37,10 +37,11 @@ class CustomFieldsControllerTest < ActionController::TestCase
|
||||||
assert_template 'index'
|
assert_template 'index'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_get_new_issue_custom_field
|
def test_new_issue_custom_field
|
||||||
get :new, :type => 'IssueCustomField'
|
get :new, :type => 'IssueCustomField'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_template 'new'
|
assert_template 'new'
|
||||||
|
assert_tag :input, :attributes => {:name => 'custom_field[name]'}
|
||||||
assert_tag :select,
|
assert_tag :select,
|
||||||
:attributes => {:name => 'custom_field[field_format]'},
|
:attributes => {:name => 'custom_field[field_format]'},
|
||||||
:child => {
|
:child => {
|
||||||
|
@ -55,16 +56,17 @@ class CustomFieldsControllerTest < ActionController::TestCase
|
||||||
:attributes => {:value => 'version'},
|
:attributes => {:value => 'version'},
|
||||||
:content => 'Version'
|
:content => 'Version'
|
||||||
}
|
}
|
||||||
|
assert_tag :input, :attributes => {:name => 'type', :value => 'IssueCustomField'}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_get_new_with_invalid_custom_field_class_should_redirect_to_list
|
def test_new_with_invalid_custom_field_class_should_render_404
|
||||||
get :new, :type => 'UnknownCustomField'
|
get :new, :type => 'UnknownCustomField'
|
||||||
assert_redirected_to '/custom_fields'
|
assert_response 404
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_post_new_list_custom_field
|
def test_create_list_custom_field
|
||||||
assert_difference 'CustomField.count' do
|
assert_difference 'CustomField.count' do
|
||||||
post :new, :type => "IssueCustomField",
|
post :create, :type => "IssueCustomField",
|
||||||
:custom_field => {:name => "test_post_new_list",
|
:custom_field => {:name => "test_post_new_list",
|
||||||
:default_value => "",
|
:default_value => "",
|
||||||
:min_length => "0",
|
:min_length => "0",
|
||||||
|
@ -85,28 +87,47 @@ class CustomFieldsControllerTest < ActionController::TestCase
|
||||||
assert_equal 1, field.trackers.size
|
assert_equal 1, field.trackers.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_get_edit
|
def test_create_with_failure
|
||||||
|
assert_no_difference 'CustomField.count' do
|
||||||
|
post :create, :type => "IssueCustomField", :custom_field => {:name => ''}
|
||||||
|
end
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'new'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_edit
|
||||||
get :edit, :id => 1
|
get :edit, :id => 1
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_template 'edit'
|
assert_template 'edit'
|
||||||
assert_tag 'input', :attributes => {:name => 'custom_field[name]', :value => 'Database'}
|
assert_tag 'input', :attributes => {:name => 'custom_field[name]', :value => 'Database'}
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_post_edit
|
def test_edit_invalid_custom_field_should_render_404
|
||||||
post :edit, :id => 1, :custom_field => {:name => 'New name'}
|
get :edit, :id => 99
|
||||||
|
assert_response 404
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update
|
||||||
|
put :update, :id => 1, :custom_field => {:name => 'New name'}
|
||||||
assert_redirected_to '/custom_fields?tab=IssueCustomField'
|
assert_redirected_to '/custom_fields?tab=IssueCustomField'
|
||||||
|
|
||||||
field = CustomField.find(1)
|
field = CustomField.find(1)
|
||||||
assert_equal 'New name', field.name
|
assert_equal 'New name', field.name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_update_with_failure
|
||||||
|
put :update, :id => 1, :custom_field => {:name => ''}
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'edit'
|
||||||
|
end
|
||||||
|
|
||||||
def test_destroy
|
def test_destroy
|
||||||
custom_values_count = CustomValue.count(:conditions => {:custom_field_id => 1})
|
custom_values_count = CustomValue.count(:conditions => {:custom_field_id => 1})
|
||||||
assert custom_values_count > 0
|
assert custom_values_count > 0
|
||||||
|
|
||||||
assert_difference 'CustomField.count', -1 do
|
assert_difference 'CustomField.count', -1 do
|
||||||
assert_difference 'CustomValue.count', - custom_values_count do
|
assert_difference 'CustomValue.count', - custom_values_count do
|
||||||
post :destroy, :id => 1
|
delete :destroy, :id => 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,15 @@ class RoutingTest < ActionController::IntegrationTest
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "custom_fields" do
|
||||||
|
should_route :get, "/custom_fields", :controller => 'custom_fields', :action => 'index'
|
||||||
|
should_route :get, "/custom_fields/new", :controller => 'custom_fields', :action => 'new'
|
||||||
|
should_route :post, "/custom_fields", :controller => 'custom_fields', :action => 'create'
|
||||||
|
should_route :get, "/custom_fields/2/edit", :controller => 'custom_fields', :action => 'edit', :id => 2
|
||||||
|
should_route :put, "/custom_fields/2", :controller => 'custom_fields', :action => 'update', :id => 2
|
||||||
|
should_route :delete, "/custom_fields/2", :controller => 'custom_fields', :action => 'destroy', :id => 2
|
||||||
|
end
|
||||||
|
|
||||||
context "documents" do
|
context "documents" do
|
||||||
should_route :get, "/projects/567/documents", :controller => 'documents', :action => 'index', :project_id => '567'
|
should_route :get, "/projects/567/documents", :controller => 'documents', :action => 'index', :project_id => '567'
|
||||||
should_route :get, "/projects/567/documents/new", :controller => 'documents', :action => 'new', :project_id => '567'
|
should_route :get, "/projects/567/documents/new", :controller => 'documents', :action => 'new', :project_id => '567'
|
||||||
|
|
|
@ -56,4 +56,23 @@ class CustomFieldTest < ActiveSupport::TestCase
|
||||||
field = CustomField.find(1)
|
field = CustomField.find(1)
|
||||||
assert field.destroy
|
assert field.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_new_subclass_instance_should_return_an_instance
|
||||||
|
f = CustomField.new_subclass_instance('IssueCustomField')
|
||||||
|
assert_kind_of IssueCustomField, f
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_subclass_instance_should_set_attributes
|
||||||
|
f = CustomField.new_subclass_instance('IssueCustomField', :name => 'Test')
|
||||||
|
assert_kind_of IssueCustomField, f
|
||||||
|
assert_equal 'Test', f.name
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_subclass_instance_with_invalid_class_name_should_return_nil
|
||||||
|
assert_nil CustomField.new_subclass_instance('WrongClassName')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_subclass_instance_with_non_subclass_name_should_return_nil
|
||||||
|
assert_nil CustomField.new_subclass_instance('Project')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue