Remove URL Friendly Name concept from Tracks. They were associated with projects and contexts. Both projects and contexts can now have a slash in the name if you so desire.

Also fixed #486 (Inline edit of project title (from individual project page) fails). Thanks to James Kebinger for reporting the issue and for the patch.

N.B. This check-in requires the REMOVAL of one line from your environment.rb file. The line to be removed reads "require 'url_friendly_name'"



git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@523 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
lukemelia 2007-04-06 03:30:20 +00:00
parent d9a194ab64
commit 3946dbf0c1
26 changed files with 70 additions and 173 deletions

View file

@ -6,14 +6,12 @@ class Context < ActiveRecord::Base
acts_as_list :scope => :user
extend NamePartFinder
include Tracks::TodoList
include UrlFriendlyName
attr_protected :user
validates_presence_of :name, :message => "context must have a name"
validates_length_of :name, :maximum => 255, :message => "context name must be less than 256 characters"
validates_uniqueness_of :name, :message => "already exists", :scope => "user_id"
validates_does_not_contain :name, :string => '/', :message => "cannot contain the slash ('/') character"
validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
def self.feed_options(user)
@ -31,10 +29,6 @@ class Context < ActiveRecord::Base
self.hide == true || self.hide == 1
end
def to_param
url_friendly_name
end
def title
name
end

View file

@ -7,14 +7,12 @@ class Project < ActiveRecord::Base
validates_presence_of :name, :message => "project must have a name"
validates_length_of :name, :maximum => 255, :message => "project name must be less than 256 characters"
validates_uniqueness_of :name, :message => "already exists", :scope =>"user_id"
validates_does_not_contain :name, :string => '/', :message => "cannot contain the slash ('/') character"
validates_does_not_contain :name, :string => ',', :message => "cannot contain the comma (',') character"
acts_as_list :scope => 'user_id = #{user_id} AND state = \'#{state}\''
acts_as_state_machine :initial => :active, :column => 'state'
extend NamePartFinder
include Tracks::TodoList
include UrlFriendlyName
state :active
state :hidden, :enter => :hide_todos, :exit => :unhide_todos
@ -45,11 +43,7 @@ class Project < ActiveRecord::Base
:description => "Lists all the projects for #{user.display_name}"
}
end
def to_param
url_friendly_name
end
def hide_todos
todos.each do |t|
unless t.completed? || t.deferred?

View file

@ -5,34 +5,14 @@ class User < ActiveRecord::Base
:order => 'position ASC',
:dependent => :delete_all do
def find_by_params(params)
if params['url_friendly_name']
find_by_url_friendly_name(params['url_friendly_name'])
elsif params['id'] && params['id'] =~ /^\d+$/
find(params['id'])
elsif params['id']
find_by_url_friendly_name(params['id'])
elsif params['context']
find_by_url_friendly_name(params['context'])
elsif params['context_id']
find_by_url_friendly_name(params['context_id'])
end
find(params['id'] || params['context_id'])
end
end
has_many :projects,
:order => 'position ASC',
:dependent => :delete_all do
def find_by_params(params)
if params['url_friendly_name']
find_by_url_friendly_name(params['url_friendly_name'])
elsif params['id'] && params['id'] =~ /^\d+$/
find(params['id'])
elsif params['id']
find_by_url_friendly_name(params['id'])
elsif params['project']
find_by_url_friendly_name(params['project'])
elsif params['project_id']
find_by_url_friendly_name(params['project_id'])
end
find(params['id'] || params['project_id'])
end
def update_positions(project_ids)
project_ids.each_with_index do |id, position|

View file

@ -21,7 +21,8 @@
%>
<% end -%>
<% if source_view_is :context %>
<%= in_place_editor_field :context, :name, {}, { :url => url_for(:controller => 'context', :action => 'update', :id => context.id, :field => 'name', :wants_render => false) } %>
<span class="in_place_editor_field" id="context_name_in_place_editor"><%= context.name %></span>
<%= in_place_editor 'context_name_in_place_editor', { :url => { :controller => 'contexts', :action => 'update', :id => context.id, :field => 'name', :wants_render => false, :escape => false} , :options=>"{method:'put'}" } %>
<% else %>
<%= link_to_context( context ) %>
<% end %>

View file

@ -5,7 +5,8 @@
<% if collapsible %>
<a href="#" class="container_toggle" id="toggle_p<%= project.id %>"><%= image_tag("collapse.png") %></a>
<% end %>
<%= in_place_editor_field :project, :name, {}, { :url => url_for(:controller => 'project', :action => 'update', :id => project.id, :field => 'name', :wants_render => false) } %>
<span class="in_place_editor_field" id="project_name_in_place_editor"><%= project.name %></span>
<%= in_place_editor 'project_name_in_place_editor', { :url => { :controller => 'projects', :action => 'update', :id => project.id, :field => 'name', :wants_render => false, :escape => false} , :options=>"{method:'put'}" } %>
</h2>
<% if @project.description -%>
<div class="project_description"><%= sanitize(@project.description) %></div>

View file

@ -64,7 +64,6 @@ AUTHENTICATION_SCHEMES = ['database']
require 'name_part_finder'
require 'todo_list'
require 'url_friendly_name'
require 'config'
require 'activerecord_base_tag_extensions' # Needed for tagging-specific extensions

View file

@ -1,20 +0,0 @@
module UrlFriendlyName
def self.included(base)
base.extend ClassMethods
end
def url_friendly_name
name.gsub(/_/,'__').gsub(/ /,'_').gsub(/\./,'__dot__')
end
module ClassMethods
def find_by_url_friendly_name(url_friendly_name)
name = url_friendly_name.gsub(/__dot__/,'.').gsub(/([^_])_(?!_)/,'\1 ').gsub(/__/,'_') #second regex replaces all single underscores with spaces
self.find_by_name(name)
end
end
end

View file

@ -30,14 +30,14 @@ class ContextsControllerTest < TodoContainerControllerTestBase
assert_rjs :call, "Form.focusFirstElement", "context-form"
end
def test_create_via_ajax_with_slash_in_name_does_not_increment_number_of_contexts
assert_ajax_create_does_not_increment_count 'foo/bar'
def test_create_via_ajax_with_comma_in_name_does_not_increment_number_of_contexts
assert_ajax_create_does_not_increment_count 'foo,bar'
end
def test_create_with_slash_in_name_fails_with_rjs
ajax_create 'foo/bar'
def test_create_with_comma_in_name_fails_with_rjs
ajax_create 'foo,bar'
assert_rjs :show, 'status'
assert_rjs :update, 'status', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the slash ('/') character</ul></div>"
assert_rjs :update, 'status', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the comma (',') character</ul></div>"
end
def test_rss_feed_content

View file

@ -57,18 +57,18 @@ class ProjectsControllerTest < TodoContainerControllerTestBase
def test_create_project_and_go_to_project_page
num_projects = Project.count
xhr :post, :create, { :project => {:name => 'Immediate Project Planning Required'}, :go_to_project => 1}
assert_js_redirected_to '/projects/Immediate_Project_Planning_Required'
assert_js_redirected_to '/projects/5'
assert_equal num_projects + 1, Project.count
end
def test_create_with_slash_in_name_does_not_increment_number_of_projects
assert_ajax_create_does_not_increment_count 'foo/bar'
def test_create_with_comma_in_name_does_not_increment_number_of_projects
assert_ajax_create_does_not_increment_count 'foo,bar'
end
def test_create_with_slash_in_name_fails_with_rjs
ajax_create 'foo/bar'
def test_create_with_comma_in_name_fails_with_rjs
ajax_create 'foo,bar'
assert_rjs :show, 'status'
assert_rjs :update, 'status', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the slash ('/') character</ul></div>"
assert_rjs :update, 'status', "<div class=\"ErrorExplanation\" id=\"ErrorExplanation\"><h2>1 error prohibited this record from being saved</h2><p>There were problems with the following fields:</p><ul>Name cannot contain the comma (',') character</ul></div>"
end
def test_todo_state_is_project_hidden_after_hiding_project

View file

@ -46,11 +46,11 @@ class ContextXmlApiTest < ActionController::IntegrationTest
end
end
def test_fails_with_slash_in_name
authenticated_post_xml_to_context_create "<request><context><name>foo/bar</name></context></request>"
def test_fails_with_comma_in_name
authenticated_post_xml_to_context_create "<request><context><name>foo,bar</name></context></request>"
assert_response 404
assert_xml_select 'errors' do
assert_select 'error', 1, 'Name cannot contain the slash (\'/\') character'
assert_select 'error', 1, 'Name cannot contain the comma (\',\') character'
end
end

View file

@ -44,27 +44,27 @@ class FeedSmokeTest < ActionController::IntegrationTest
end
def test_all_actions_in_context_rss
assert_success "/contexts/agenda/todos.rss?token=#{ users(:admin_user).word }"
assert_success "/contexts/1/todos.rss?token=#{ users(:admin_user).word }"
end
def test_all_actions_in_context_txt
assert_success "/contexts/agenda/todos.txt?token=#{ users(:admin_user).word }"
assert_success "/contexts/1/todos.txt?token=#{ users(:admin_user).word }"
end
def test_all_actions_in_context_ical
assert_success "/contexts/agenda/todos.ics?token=#{ users(:admin_user).word }"
assert_success "/contexts/1/todos.ics?token=#{ users(:admin_user).word }"
end
def test_all_actions_in_project_rss
assert_success "/projects/Build_a_working_time_machine/todos.rss?token=#{ users(:admin_user).word }"
assert_success "/projects/1/todos.rss?token=#{ users(:admin_user).word }"
end
def test_all_actions_in_project_txt
assert_success "/projects/Build_a_working_time_machine/todos.txt?token=#{ users(:admin_user).word }"
assert_success "/projects/1/todos.txt?token=#{ users(:admin_user).word }"
end
def test_all_actions_in_project_ical
assert_success "/projects/Build_a_working_time_machine/todos.ics?token=#{ users(:admin_user).word }"
assert_success "/projects/1/todos.ics?token=#{ users(:admin_user).word }"
end
def test_all_actions_due_today_or_earlier_rss
@ -120,7 +120,7 @@ class FeedSmokeTest < ActionController::IntegrationTest
p.hide!
assert_success "/projects.txt?token=#{ users(:admin_user).word }"
end
private
def assert_success(url)

View file

@ -43,9 +43,9 @@ class ProjectXmlApiTest < ActionController::IntegrationTest
assert_response_and_body 404, "Name project name must be less than 256 characters"
end
def test_fails_with_slash_in_name
authenticated_post_xml_to_project_create "<request><project><name>foo/bar</name></project></request>"
assert_response_and_body 404, "Name cannot contain the slash ('/') character"
def test_fails_with_comma_in_name
authenticated_post_xml_to_project_create "<request><project><name>foo,bar</name></project></request>"
assert_response_and_body 404, "Name cannot contain the comma (',') character"
end
def test_creates_new_project

View file

@ -0,0 +1,10 @@
setup :fixtures => :all
login :as => 'admin'
open "/contexts/1"
click "context_name_in_place_editor"
wait_for_element_present "css=#context_name_in_place_editor-inplaceeditor input.editor_field"
type "css=#context_name_in_place_editor-inplaceeditor input.editor_field", "Test Foo"
click "css=#context_name_in_place_editor-inplaceeditor input.editor_ok_button"
wait_for_text "context_name_in_place_editor", "Test Foo"
open "/contexts/1"
wait_for_text "context_name_in_place_editor", "Test Foo"

View file

@ -1,5 +1,5 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
click_and_wait "css=#note_1 .link_to_notes"
assert_element_present "note_1"

View file

@ -1,9 +1,9 @@
setup :fixtures => :all
next_available_todo_id = 18
login :as => 'admin'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
include_partial 'project_detail/add_deferred_todo'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
click "edit_icon_todo_#{next_available_todo_id}"
wait_for_element_present "show_from_todo_#{next_available_todo_id}"
type "show_from_todo_#{next_available_todo_id}", ""

View file

@ -1,6 +1,6 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
click "edit_icon_todo_15"
wait_for_element_present "show_from_todo_15"
type "show_from_todo_15", ""

View file

@ -1,6 +1,6 @@
setup :fixtures => :all
login :as => 'admin'
open '/projects/Build_a_working_time_machine'
open '/projects/1'
assert_checked 'project_state_active', 'ignored'
assert_attribute 'css=#project_status .active span', 'class', 'active_state'
assert_attribute 'css=#project_status .hidden span', 'class', 'inactive_state'
@ -9,6 +9,6 @@ click 'project_state_hidden'
wait_for_attribute 'css=#project_status .active span', 'class', 'inactive_state'
wait_for_attribute 'css=#project_status .hidden span', 'class', 'active_state'
assert_text 'badge_count', '2'
open '/projects/Build_a_working_time_machine'
open '/projects/1'
assert_text 'badge_count', '2'
assert_checked 'project_state_hidden', 'ignored'

View file

@ -1,6 +1,6 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
click "edit_icon_todo_5"
wait_for_element_present "show_from_todo_5"
type "project_name_todo_5", ""

View file

@ -1,5 +1,5 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/Make_more_money_than_Billy_Gates"
open "/projects/2"
include_partial 'project_detail/add_deferred_todo'
assert_not_visible "tickler-empty-nd"

View file

@ -1,6 +1,6 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
click "edit_icon_todo_5"
wait_for_element_present "show_from_todo_5"
type "show_from_todo_5", "1/1/2030"

View file

@ -0,0 +1,10 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/1"
click "project_name_in_place_editor"
wait_for_element_present "css=#project_name_in_place_editor-inplaceeditor input.editor_field"
type "css=#project_name_in_place_editor-inplaceeditor input.editor_field", "Test Foo"
click "css=#project_name_in_place_editor-inplaceeditor input.editor_ok_button"
wait_for_text "project_name_in_place_editor", "Test Foo"
open "/projects/1"
wait_for_text "project_name_in_place_editor", "Test Foo"

View file

@ -1,6 +1,6 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
include_partial 'project_detail/add_deferred_todo'
click "xpath=//div[@id='tickler'] //div[@id='todo_15'] //input[@class='item-checkbox']"
wait_for_element_present "xpath=//div[@id='completed'] //div[@id='todo_15']"

View file

@ -1,5 +1,5 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/Build_a_working_time_machine"
open "/projects/1"
click "xpath=//div[@id='tickler'] //div[@id='todo_15'] //input[@class='item-checkbox']"
wait_for_visible "tickler-empty-nd"

View file

@ -32,14 +32,6 @@ class ContextTest < Test::Unit::TestCase
assert_equal "already exists", newcontext.errors.on(:name)
end
def test_validate_name_does_not_contain_slash
newcontext = Context.new
newcontext.name = "phone/telegraph"
assert !newcontext.save
assert_equal 1, newcontext.errors.count
assert_equal "cannot contain the slash ('/') character", newcontext.errors.on(:name)
end
def test_validate_name_does_not_contain_comma
newcontext = Context.new
newcontext.name = "phone,telegraph"
@ -85,28 +77,8 @@ class ContextTest < Test::Unit::TestCase
assert_equal 2, Context.find(@agenda.id).done_todos.size
end
def test_url_friendly_name_for_name_with_spaces
assert_url_friendly_name_converts_properly 'any computer', 'any_computer'
end
def test_url_friendly_name_for_name_without_spaces
assert_url_friendly_name_converts_properly 'NoSpacesHere', 'NoSpacesHere'
end
def test_url_friendly_name_for_name_with_underscores
assert_url_friendly_name_converts_properly 'there is an_underscore', 'there_is_an__underscore'
end
def assert_url_friendly_name_converts_properly(name, url_friendly_name)
context = Context.create(:name => name)
assert_equal url_friendly_name, context.url_friendly_name
found_context = Context.find_by_url_friendly_name(url_friendly_name)
assert_not_nil context
assert_equal context.id, found_context.id
end
def test_to_param_returns_url_friendly_name
assert_equal 'agenda', @agenda.to_param
def test_to_param_returns_id
assert_equal '1', @agenda.to_param
end
def test_title_reader_returns_name

View file

@ -30,15 +30,7 @@ class ProjectTest < Test::Unit::TestCase
assert_equal 1, newproj.errors.count
assert_equal "already exists", newproj.errors.on(:name)
end
def test_validate_name_does_not_contain_slash
newproj = Project.new
newproj.name = "Save Earth/Mankind from Evil"
assert !newproj.save
assert_equal 1, newproj.errors.count
assert_equal "cannot contain the slash ('/') character", newproj.errors.on(:name)
end
def test_validate_name_does_not_contain_comma
newproj = Project.new
newproj.name = "Buy iPhones for Luke,bsag,David Allen"
@ -114,33 +106,9 @@ class ProjectTest < Test::Unit::TestCase
t.save!
assert_equal 2, Project.find(@timemachine.id).deferred_todos.size
end
def test_url_friendly_name_for_name_with_spaces
assert_url_friendly_name_converts_properly 'Build a playhouse', 'Build_a_playhouse'
end
def test_url_friendly_name_for_name_without_spaces
assert_url_friendly_name_converts_properly 'NoSpacesHere', 'NoSpacesHere'
end
def test_url_friendly_name_for_name_with_an_underscore
assert_url_friendly_name_converts_properly 'there is an_underscore', 'there_is_an__underscore'
end
def test_url_friendly_name_for_name_with_a_dot
assert_url_friendly_name_converts_properly 'hello.com', 'hello__dot__com'
end
def assert_url_friendly_name_converts_properly(name, url_friendly_name)
project = Project.create(:name => name)
assert_equal url_friendly_name, project.url_friendly_name
found_project = Project.find_by_url_friendly_name(url_friendly_name)
assert_not_nil project
assert_equal project.id, found_project.id
end
def test_to_param_returns_url_friendly_name
assert_equal 'Build_a_working_time_machine', @timemachine.to_param
def test_to_param_returns_id
assert_equal '1', @timemachine.to_param
end
def test_null_object

View file

@ -227,29 +227,17 @@ class UserTest < Test::Unit::TestCase
def test_find_context_by_params
u = @admin_user
c = u.contexts.find_by_params('url_friendly_name' => 'agenda')
assert_equal contexts(:agenda), c
c = u.contexts.find_by_params('id' => 'agenda')
assert_equal contexts(:agenda), c
c = u.contexts.find_by_params('id' => '1')
assert_equal contexts(:agenda), c
c = u.contexts.find_by_params('context' => 'agenda')
assert_equal contexts(:agenda), c
c = u.contexts.find_by_params('context_id' => 'agenda')
c = u.contexts.find_by_params('context_id' => '1')
assert_equal contexts(:agenda), c
end
def test_find_project_by_params
u = @admin_user
p = u.projects.find_by_params('url_friendly_name' => 'Build_a_working_time_machine')
assert_equal projects(:timemachine), p
p = u.projects.find_by_params('id' => 'Build_a_working_time_machine')
assert_equal projects(:timemachine), p
p = u.projects.find_by_params('id' => '1')
assert_equal projects(:timemachine), p
p = u.projects.find_by_params('project' => 'Build_a_working_time_machine')
assert_equal projects(:timemachine), p
p = u.projects.find_by_params('project_id' => 'Build_a_working_time_machine')
p = u.projects.find_by_params('project_id' => '1')
assert_equal projects(:timemachine), p
end