Merge branch 'groups_reincarnation' into staging

Conflicts:
	app/models/ability.rb
	app/models/project.rb
	config/environments/production.rb
This commit is contained in:
George Vinogradov 2011-12-05 17:16:32 +04:00
commit 2f5ce7cebe
29 changed files with 614 additions and 42 deletions

View File

@ -15,8 +15,13 @@ class ApplicationController < ActionController::Base
protected
def get_owner
params['user_id'] && User.find_by_id(params['user_id']) ||
params['group_id'] && Group.find_by_id(params['group_id']) || current_user
# params['user_id'] && User.find_by_id(params['user_id']) ||
# params['group_id'] && Group.find_by_id(params['group_id']) || current_user
if parent and (parent.is_a? User or parent.is_a? Group)
parent
else
current_user
end
end
def layout_by_resource

View File

@ -29,8 +29,11 @@ class CollaboratorsController < ApplicationController
def update
all_user_ids = []
all_groups_ids = []
puts params.inspect
Relation::ROLES.each { |r|
all_user_ids = all_user_ids | params[r.to_sym].keys if params[r.to_sym]
all_user_ids = all_user_ids | params['user'][r.to_sym].keys if params['user'][r.to_sym]
all_groups_ids = all_groups_ids | params['group'][r.to_sym].keys if params['group'][r.to_sym]
}
# Remove relations
@ -40,11 +43,17 @@ class CollaboratorsController < ApplicationController
users_for_removing.each do |u|
Relation.by_object(u).by_target(@project).each {|r| r.destroy}
end
groups_for_removing = @project.groups.select do |u|
!all_groups_ids.map{|k| k.to_i}.include? u.id and @project.owner != u
end
groups_for_removing.each do |u|
Relation.by_object(u).by_target(@project).each {|r| r.destroy}
end
# Create relations
Relation::ROLES.each { |r|
#users_for_creating = users_for_creating params[:user].keys.map{|p| p.to_i} - @project.collaborators.map(&:id)
params[r.to_sym].keys.each { |u|
params['user'][r.to_sym].keys.each { |u|
if relation = @project.relations.find_by_object_id_and_object_type(u, 'User')
relation.update_attribute(:role, r)
else
@ -53,7 +62,17 @@ class CollaboratorsController < ApplicationController
puts r
relation.save!
end
} if params[r.to_sym]
} if params['user'][r.to_sym]
params['group'][r.to_sym].keys.each { |u|
if relation = @project.relations.find_by_object_id_and_object_type(u, 'Group')
relation.update_attribute(:role, r)
else
relation = @project.relations.build(:object_id => u, :object_type => 'Group', :role => r)
puts relation.inspect
puts r
relation.save!
end
} if params['group'][r.to_sym]
}
if @project.save

View File

@ -1,12 +1,27 @@
# coding: UTF-8
class GroupsController < ApplicationController
is_related_controller!
belongs_to :user, :optional => true
before_filter :authenticate_user!
before_filter :find_group, :only => [:show, :edit, :update, :destroy]
load_and_authorize_resource
def index
@groups = Group.paginate(:page => params[:group_page])
puts parent.inspect
@groups = if parent? and !parent.nil?
parent.groups
else
Group
end.accessible_by(current_ability)
@groups = if params[:query]
@groups.where(["name LIKE ?", "%#{params[:query]}%"])
else
@groups
end.paginate(:page => params[:group_page])
end
def show
@ -24,13 +39,18 @@ class GroupsController < ApplicationController
def create
@group = Group.new params[:group]
@group.owner = current_user
@group.members << current_user
if @group.save
@group.owner = if parent? and parent.is_a? User
parent
else
current_user
end
if @group.save!
flash[:notice] = t('flash.group.saved')
redirect_to edit_group_path(@group)
else
flash[:error] = t('flash.group.save_error')
flash[:warning] = @project.errors[:base]
render :action => :new
end
end

View File

@ -0,0 +1,76 @@
class MembersController < ApplicationController
before_filter :authenticate_user!
is_related_controller!
belongs_to :group, :optional => true
# before_filter :find_target
before_filter :find_users
def index
redirect_to edit_group_members_path(parent)
end
def show
end
def new
end
def edit
if params[:id]
@user = User.find params[:id]
render :edit_rights and return
end
end
def create
end
def update
all_user_ids = []
Relation::ROLES.each { |r|
all_user_ids = all_user_ids | params[r.to_sym].keys if params[r.to_sym]
}
# Remove relations
users_for_removing = parent.members.select do |u|
!all_user_ids.map{|k| k.to_i}.include? u.id and parent.owner != u
end
users_for_removing.each do |u|
Relation.by_object(u).by_target(parent).each {|r| r.destroy}
end
# Create relations
Relation::ROLES.each { |r|
#users_for_creating = users_for_creating params[:user].keys.map{|p| p.to_i} - @project.collaborators.map(&:id)
params[r.to_sym].keys.each { |u|
if relation = parent.objects.find_by_object_id_and_object_type(u, 'User')
relation.update_attribute(:role, r)
else
relation = parent.objects.build(:object_id => u, :object_type => 'User', :role => r)
puts relation.inspect
puts r
relation.save!
end
} if params[r.to_sym]
}
if parent.save
flash[:notice] = t("flash.members.successfully_changed")
else
flash[:error] = t("flash.members.error_in_changing")
end
redirect_to parent_path
end
def destroy
end
protected
def find_users
@users = User.all
end
end

View File

@ -1,4 +1,8 @@
class ProjectsController < ApplicationController
is_related_controller!
belongs_to :user, :group, :polymorphic => true, :optional => true
before_filter :authenticate_user!, :except => :auto_build
before_filter :find_project, :only => [:show, :edit, :update, :destroy, :fork, :build, :process_build]
before_filter :get_paths, :only => [:new, :create, :edit, :update]
@ -6,11 +10,19 @@ class ProjectsController < ApplicationController
load_and_authorize_resource
def index
if params[:query]
@projects = Project.accessible_by(current_ability).where(:name => params[:query]).paginate(:page => params[:project_page])
# puts parent.inspect
# puts parent.is_a? User
@projects = if parent? and !parent.nil?
parent.projects
else
@projects = Project.accessible_by(current_ability).paginate(:page => params[:project_page])
end
Project
end.accessible_by(current_ability)
@projects = if params[:query]
@projects.where(["name LIKE ?", "%#{params[:query]}%"])
else
@projects
end.paginate(:page => params[:project_page])
@own_projects = current_user.own_projects
@part_projects = current_user.projects - @own_projects
@ -30,6 +42,7 @@ class ProjectsController < ApplicationController
def create
@project = Project.new params[:project]
@project.owner = get_owner
# puts @project.owner.inspect
if @project.save
flash[:notice] = t('flash.project.saved')
@ -46,7 +59,7 @@ class ProjectsController < ApplicationController
flash[:notice] = t('flash.project.saved')
redirect_to @project
else
@project.save!
@project.save
flash[:error] = t('flash.project.save_error')
render :action => :edit
end

View File

@ -29,12 +29,19 @@ class Ability
can [:index, :destroy], AutoBuildList, :project_id => user.own_project_ids
# If rules goes one by one CanCan joins them by 'OR' sql operator
can :read, Project, :visibility => 'open'
can :read, Group
can :read, User
can :manage_collaborators, Project do |project|
project.relations.exists? :object_id => user.id, :object_type => 'User', :role => 'admin'
end
can :manage_members, Group do |group|
group.objects.exists? :object_id => user.id, :object_type => 'User', :role => 'admin'
end
# Put here model names which objects can user create
can :create, Project
can :create, Group
can :publish, BuildList do |build_list|
build_list.can_published? && build_list.project.relations.exists?(:object_type => 'User', :object_id => user.id)
end
@ -60,6 +67,10 @@ class Ability
product.platform.relations.exists?(:role => 'admin', :object_type => 'User', :object_id => user.id)
end
can [:read, :update], Group, groups_in_relations_with(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) do |group|
group.objects.exists?(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id)
end
can :manage, Platform, :owner_type => 'User', :owner_id => user.id
can :manage, Platform, platforms_in_relations_with(:role => 'admin', :object_type => 'User', :object_id => user.id) do |platform|
platform.relations.exists?(:role => 'admin', :object_type => 'User', :object_id => user.id)
@ -128,7 +139,7 @@ class Ability
# Sub query for platforms, projects relations
# TODO: Replace table names list by method_missing way
%w[platforms projects products repositories].each do |table_name|
%w[platforms projects products repositories groups].each do |table_name|
define_method table_name + "_in_relations_with" do |opts|
query = "#{ table_name }.id IN (SELECT target_id FROM relations WHERE relations.target_type = '#{ table_name.singularize.camelize }'"
opts.each do |key, value|

View File

@ -20,6 +20,14 @@ class Group < ActiveRecord::Base
delegate :ssh_key, :to => :owner
after_create :add_owner_to_members
include Modules::Models::PersonalRepository
include Modules::Models::Owner
protected
def add_owner_to_members
Relation.create_with_role(self.owner, self, 'admin')
# members << self.owner if !members.exists?(:id => self.owner.id)
end
end

View File

@ -5,6 +5,21 @@ class Relation < ActiveRecord::Base
ROLES = %w[reader writer admin]
validates :role, :inclusion => {:in => ROLES}
before_validation :add_default_role
scope :by_object, lambda {|obj| {:conditions => ['object_id = ? AND object_type = ?', obj.id, obj.class.to_s]}}
scope :by_target, lambda {|tar| {:conditions => ['target_id = ? AND target_type = ?', tar.id, tar.class.to_s]}}
def self.create_with_role(object, target, role)
r = new
r.object = object
r.target = target
r.role = role
r.save
end
protected
def add_default_role
self.role = ROLES.first if role.nil? || role.empty?
end
end

View File

@ -22,28 +22,29 @@
= link_to user.name, user_path(user)
%td
- Relation::ROLES.each do |role|
= check_box_tag "#{ role }[#{user.id}]", '1', ((@project.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"}
= label_tag "#{ role }[#{user.id}]", t("layout.collaborators.roles.#{ role }")
= check_box_tag "user[#{ role }][#{user.id}]", '1', ((@project.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"}
= label_tag "user[#{ role }][#{user.id}]", t("layout.collaborators.roles.#{ role }")
%td
= user.uname
/%h2.title= t("layout.groups.list_header")
/%table.table
/ %tr
/ %th.first ID
/ %th= t("activerecord.attributes.group.name")
/ %th= t("activerecord.attributes.group.uname")
/ %th.last= t("layout.collaborators.add")
/ - @groups.each do |group|
/ %tr{:class => cycle("odd", "even")}
/ %td
/ = group.id
/ %td
/ = link_to group.name, group_path(group)
/ %td
/ = group.uname
/ %td.last
/ = check_box_tag "group[#{group.id}]", '1', (@project.groups.include? group) ? :checked : nil
/ = label_tag "group[#{group.id}]", t("layout.collaborators.add")
%h2.title= t("layout.groups.list_header")
%table.table
%tr
%th.first ID
%th= t("activerecord.attributes.group.name")
%th= t("activerecord.attributes.group.uname")
%th.last= t("layout.collaborators.add")
- @groups.each do |group|
%tr{:class => cycle("odd", "even")}
%td
= group.id
%td
= link_to group.name, group_path(group)
%td
- Relation::ROLES.each do |role|
= check_box_tag "group[#{role}][#{group.id}]", '1', ((@project.relations.exists? :object_id => group.id, :object_type => 'Group', :role => role) ? :checked : nil), {:class => "user_role_chbx"}
= label_tag "group[#{role}][#{group.id}]", t("layout.collaborators.roles.#{role}")
%td
= group.uname
.group.navform.wat-cf
%button.button{:type => "submit"}
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save"))

View File

@ -1,5 +1,15 @@
.block.notice
%h3= t("layout.groups.members")
.content
- @group.members.each do |member|
%p= link_to member.name, member
%p
%ul
- @group.members.each do |user|
%li
- if can? :read, user
= link_to user.name, user_path(user)
- else
= user.name
- if (@group.owner == user)
= '(' + t("layout.owner") + ')'
%br
= link_to t("layout.groups.edit_members"), edit_group_members_path(@group) if can? :manage_members, @group

View File

@ -25,6 +25,9 @@
-if can? :index, Project
%li{:class => controller.controller_path == 'projects' ? 'active' : '' }
%a{:href => projects_path}= t("layout.menu.projects")
-if can? :index, Group
%li{:class => controller.controller_path == 'groups' ? 'active' : '' }
%a{:href => groups_path}= t("layout.menu.groups")
-if can? :index, Download
%li{:class => controller.controller_path == 'downloads' ? 'active' : '' }
%a{:href => downloads_path}= t("layout.menu.downloads")

View File

@ -0,0 +1,35 @@
.block
.secondary-navigation
%ul.wat-cf
%li.first= link_to t("layout.members.back_to_group"), parent_path
%li.active= link_to t("layout.members.edit"), edit_group_members_path(@group)
.content
.inner
= form_tag group_members_path(parent) do
%h2.title= t("layout.users.list_header")
%table.table
%tr
%th.first ID
%th= t("activerecord.attributes.user.name")
%th= t("activerecord.attributes.user.roles")
%th= t("activerecord.attributes.user.uname")
- #TODO: Replace this Chelyabinsk add/remove collaborators method by more human method
- @users.each do |user|
%tr{:class => cycle("odd", "even")}
%td
= user.id
%td
= link_to user.name, user_path(user)
%td
- Relation::ROLES.each do |role|
= check_box_tag "#{ role }[#{user.id}]", '1', ((parent.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"}
= label_tag "#{ role }[#{user.id}]", t("layout.members.roles.#{ role }")
%td
= user.uname
.group.navform.wat-cf
%button.button{:type => "submit"}
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save"))
= t("layout.save")
%span.text_button_padding= t("layout.or")
= link_to t("layout.cancel"), group_path(parent), :class => "text_button_padding link_button"

View File

@ -13,8 +13,18 @@
= user.name
- if (@project.owner == user)
= '(' + t("layout.owner") + ')'
%br
/%br
-# if can? :update, @project
%p
%b
= "#{t("layout.projects.groups")}:"
%ul
- @project.groups.each do |group|
%li
= link_to group.name, group_path(group)
- if (@project.owner == group)
= '(' + t("layout.owner") + ')'
%br
= link_to t("layout.projects.edit_collaborators"), edit_project_collaborators_path(@project) if can? :manage_collaborators, @project
/ %p

View File

@ -223,6 +223,10 @@ ru:
roles_header: Роли для
add_role: Добавить/Удалить роль
members:
back_to_group: Вернуться к группе
edit: Редактировать список
roles: Роли
groups:
list: Список
@ -235,6 +239,7 @@ ru:
show: Группа
back_to_the_list: К списку групп
confirm_delete: Вы уверены, что хотите удалить эту группу?
edit_members: Изменить список участников
users:
list: Список
@ -321,6 +326,10 @@ ru:
successfully_changed: Список коллабораторов успешно изменен
error_in_changing: Ошибка изменения списка коллабораторов
members:
successfully_changed: Список участников успешно изменен
error_in_changing: Ошибка изменения списка участников
auto_build_list:
success: Сборка проекта автоматизорована!
failed: Не удалось автоматизировать сборку!

View File

@ -6,7 +6,9 @@ Rosa::Application.routes.draw do
get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru'
end
resources :users
resources :users do
resources :groups, :only => [:new, :create, :index]
end
resources :event_logs, :only => :index
@ -105,10 +107,22 @@ Rosa::Application.routes.draw do
end
end
resources :groups do
resources :members, :only => [:index, :edit, :update] do
collection do
get :edit
post :update
end
member do
post :update
end
end
end
resources :users, :groups do
resources :platforms, :only => [:new, :create]
resources :projects, :only => [:new, :create]
resources :projects, :only => [:new, :create, :index]
resources :repositories, :only => [:new, :create]
end

View File

@ -0,0 +1,20 @@
Copyright (c) 2011 [name of plugin creator]
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

13
vendor/plugins/related_models/README vendored Normal file
View File

@ -0,0 +1,13 @@
RelatedModels
=============
Introduction goes here.
Example
=======
Example goes here.
Copyright (c) 2011 [name of plugin creator], released under the MIT license

23
vendor/plugins/related_models/Rakefile vendored Normal file
View File

@ -0,0 +1,23 @@
require 'rake'
require 'rake/testtask'
require 'rdoc/task'
desc 'Default: run unit tests.'
task :default => :test
desc 'Test the related_models plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
desc 'Generate documentation for the related_models plugin.'
RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'RelatedModels'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end

View File

@ -0,0 +1,23 @@
module RelatedModels
class Base < ::ApplicationController
def self.is_child!(base)
base.class_eval do
# include InheritedResources::Actions
# include InheritedResources::BaseHelpers
extend RelatedModels::ClassMethods
extend RelatedModels::UrlHelpers
helper_method :parent_url, :parent_path
self.class_attribute :parents_symbols, :resources_configuration, :instance_writer => false
self.parents_symbols ||= []
self.resources_configuration ||= {}
protected :parents_symbols, :resources_configuration, :parents_symbols?, :resources_configuration?
end
end
is_child!(self)
end
end

2
vendor/plugins/related_models/init.rb vendored Normal file
View File

@ -0,0 +1,2 @@
# Include hook code here
require 'related_models'

View File

@ -0,0 +1 @@
# Install hook code here

View File

@ -0,0 +1,14 @@
# RelatedModels
module RelatedModels
autoload :ClassMethods, 'related_models/class_methods'
autoload :BelongsToHelpers, 'related_models/belongs_to_helpers'
autoload :PolymorphicHelpers, 'related_models/polymorphic_helpers'
autoload :UrlHelpers, 'related_models/url_helpers'
end
class ActionController::Base
#include ClassMethods
def self.is_related_controller!
RelatedModels::Base.is_child!(self)
end
end

View File

@ -0,0 +1,39 @@
module RelatedModels
module BelongsToHelpers
protected
def parent?
true
end
def parent
@parent ||= find_parent
end
def parent_type
parent.class.name.underscore.to_sym
end
private
def symbols_for_association_chain
parents_symbols.compact
end
def find_parent
k = params.symbolize_keys.keys
res = nil
symbols_for_association_chain.reverse.each do |sym|
if k.include? resources_configuration[sym][:param]
parent_config = resources_configuration[sym]
res = parent_config[:parent_class].send(parent_config[:finder], params[parent_config[:param]])
break
end
end
unless res
raise "Couldn't find parent"
end
return res
end
end
end

View File

@ -0,0 +1,68 @@
module RelatedModels
module ClassMethods
protected
def belongs_to(*symbols)
options = symbols.extract_options!
options.symbolize_keys!
options.assert_valid_keys(:polymorphic, :optional, :finder)
optional = options.delete(:optional)
polymorphic = options.delete(:polymorphic)
finder = options.delete(:finder)
include BelongsToHelpers if self.parents_symbols.empty?
acts_as_polymorphic! if polymorphic || optional
raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty?
raise ArgumentError, 'You cannot define multiple associations with options: #{options.keys.inspect} to belongs to.' unless symbols.size == 1 || options.empty?
symbols.each do |symbol|
symbol = symbol.to_sym
if polymorphic || optional
self.parents_symbols << :polymorphic unless self.parents_symbols.include?(:polymorphic)
self.resources_configuration[:polymorphic] ||= {}
self.resources_configuration[:polymorphic][:symbols] ||= []
self.resources_configuration[:polymorphic][:symbols] << symbol
self.resources_configuration[:polymorphic][:optional] ||= optional
else
self.parents_symbols << symbol
end
config = self.resources_configuration[symbol] = {}
config[:parent_class] = begin
class_name = symbol.to_s.pluralize.classify
class_name.constantize
rescue NameError => e
raise unless e.message.include?(class_name)
nil
end
config[:collection_name] = symbol.to_s.pluralize.to_sym
config[:instance_name] = symbol
config[:param] = :"#{symbol}_id"
config[:route_name] = symbol
config[:finder] = finder || :find
end
create_resources_url_helpers!
helper_method :parent, :parent?
end
private
def acts_as_polymorphic! #:nodoc:
unless self.parents_symbols.include?(:polymorphic)
include PolymorphicHelpers
helper_method :parent_type, :parent_class
end
end
def inherited(base)
super(base)
end
end
end

View File

@ -0,0 +1,80 @@
module RelatedModels
module PolymorphicHelpers
protected
# Returns the parent type. A Comments class can have :task, :file, :note
# as parent types.
#
def parent_type
@parent_type
end
def parent_class
parent.class if @parent_type
end
# Returns the parent object. They are also available with the instance
# variable name: @task, @file, @note...
#
def parent
k = params.symbolize_keys.keys
res = nil
symbols_for_association_chain.reverse.each do |sym|
if k.include? resources_configuration[sym][:param]
parent_config = resources_configuration[sym]
res = parent_config[:parent_class].send(parent_config[:finder], params[parent_config[:param]])
break
end
end
return res
end
# If the polymorphic association is optional, we might not have a parent.
#
def parent?
if resources_configuration[:polymorphic][:optional]
parents_symbols.size > 1 || !@parent_type.nil?
else
true
end
end
private
# Maps parents_symbols to build association chain.
#
# If the parents_symbols find :polymorphic, it goes through the
# params keys to see which polymorphic parent matches the given params.
#
# When optional is given, it does not raise errors if the polymorphic
# params are missing.
#
def symbols_for_association_chain #:nodoc:
polymorphic_config = resources_configuration[:polymorphic]
parents_symbols.map do |symbol|
if symbol == :polymorphic
params_keys = params.keys
keys = polymorphic_config[:symbols].map do |poly|
params_keys.include?(resources_configuration[poly][:param].to_s) ? poly : nil
end.compact
if keys.empty?
raise ScriptError, "Could not find param for polymorphic association. The request" <<
"parameters are #{params.keys.inspect} and the polymorphic " <<
"associations are #{polymorphic_config[:symbols].inspect}." unless polymorphic_config[:optional]
nil
else
@parent_type = keys[-1].to_sym
@parent_types = keys.map(&:to_sym)
end
else
symbol
end
end.flatten.compact
end
end
end

View File

@ -0,0 +1,28 @@
module RelatedModels
module UrlHelpers
protected
def create_resources_url_helpers!
segment = if parents_symbols.include? :polymorphic
:polymorphic
else
resources_configuration[symbols_for_association_chain.first][:route_name]
end
unless parent.nil?
class_eval <<-URL_HELPERS, __FILE__, __LINE__
protected
def parent_path(*given_args)
given_options = given_args.extract_options!
#{segment}_path(parent, given_options)
end
def parent_url(*given_args)
given_options = given_args.extract_options!
#{segment}_url(parent, given_options)
end
URL_HELPERS
end
end
end
end

View File

@ -0,0 +1,8 @@
require 'test_helper'
class RelatedModelsTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end

View File

@ -0,0 +1,3 @@
require 'rubygems'
require 'test/unit'
require 'active_support'

View File

@ -0,0 +1 @@
# Uninstall hook code here