Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

collection_from_association now works with Proc conditions for the as…

…sociations
  • Loading branch information...
commit 70986a207f29d15183bc1ed17648058be02930d9 1 parent b11e143
@eneagoe eneagoe authored
View
45 lib/formtastic/inputs/base/collections.rb
@@ -2,18 +2,18 @@ module Formtastic
module Inputs
module Base
module Collections
-
+
def label_method
label_and_value_method(raw_collection).first
end
-
+
def value_method
label_and_value_method(raw_collection).last
end
-
+
def label_and_value_method(_collection, grouped=false)
sample = _collection.first || _collection.last
-
+
case sample
when Array
label, value = :first, :last
@@ -22,36 +22,36 @@ def label_and_value_method(_collection, grouped=false)
when String, NilClass
label, value = :to_s, :to_s
end
-
+
# Order of preference: user supplied method, class defaults, auto-detect
label = (grouped ? options[:grouped_label_method] : options[:member_label]) || label || builder.collection_label_methods.find { |m| sample.respond_to?(m) }
value = (grouped ? options[:grouped_value_method] : options[:member_value]) || value || builder.collection_value_methods.find { |m| sample.respond_to?(m) }
-
+
[label, value]
end
-
+
def raw_collection
@raw_collection ||= (collection_from_options || collection_from_association || collection_for_boolean)
end
-
+
def collection
# Return if we have a plain string
return raw_collection if raw_collection.instance_of?(String) || raw_collection.instance_of?(ActiveSupport::SafeBuffer)
-
+
# Return if we have an Array of strings, fixnums or arrays
return raw_collection if (raw_collection.instance_of?(Array) || raw_collection.instance_of?(Range)) &&
[Array, Fixnum, String, Symbol].include?(raw_collection.first.class) &&
!(options.include?(:member_label) || options.include?(:member_value))
-
+
raw_collection.map { |o| [send_or_call(label_method, o), send_or_call(value_method, o)] }
end
-
+
def collection_from_options
items = options[:collection]
items = items.to_a if items.is_a?(Hash)
items
end
-
+
def collection_from_association
if reflection
raise PolymorphicInputWithoutCollectionError.new("A collection must be supplied for #{method} input. Collections cannot be guessed for polymorphic associations.") if reflection.options && reflection.options[:polymorphic] == true
@@ -59,27 +59,26 @@ def collection_from_association
find_options_from_options = options[:find_options] || {}
conditions_from_options = find_options_from_options[:conditions] || {}
conditions_from_reflection = reflection.options && reflection.options[:conditions] || {}
-
+ conditions_from_reflection = conditions_from_reflection.call if conditions_from_reflection.is_a?(Proc)
+
if conditions_from_options.any?
- reflection.klass.where(
- conditions_from_reflection.merge(conditions_from_options)
- )
+ reflection.klass.scoped(:conditions => conditions_from_reflection).where(conditions_from_options)
else
find_options_from_options.merge!(:include => group_by) if self.respond_to?(:group_by) && group_by
- reflection.klass.where(conditions_from_reflection.merge(find_options_from_options))
+ reflection.klass.scoped(:conditions => conditions_from_reflection).where(find_options_from_options)
end
end
end
-
+
def collection_for_boolean
true_text = options[:true] || Formtastic::I18n.t(:yes)
false_text = options[:false] || Formtastic::I18n.t(:no)
-
+
# TODO options[:value_as_class] = true unless options.key?(:value_as_class)
-
+
[ [true_text, true], [false_text, false] ]
end
-
+
def send_or_call(duck, object)
if duck.respond_to?(:call)
duck.call(object)
@@ -87,14 +86,14 @@ def send_or_call(duck, object)
object.send(duck)
end
end
-
+
# Avoids an issue where `send_or_call` can be a String and duck can be something simple like
# `:first`, which obviously String responds to.
def send_or_call_or_object(duck, object)
return object if object.is_a?(String) # TODO what about other classes etc?
send_or_call(duck, object)
end
-
+
end
end
end
View
11 spec/inputs/select_input_spec.rb
@@ -208,7 +208,7 @@
end
it "should call author.find with association conditions" do
- ::Author.should_receive(:where).with(:active => true)
+ ::Author.should_receive(:scoped).with(:conditions => {:active => true})
semantic_form_for(@new_post) do |builder|
concat(builder.input(:author, :as => :select))
@@ -216,7 +216,8 @@
end
it "should call author.find with association conditions and find_options conditions" do
- ::Author.should_receive(:where).with({:active => true, :publisher => true})
+ ::Author.should_receive(:scoped).with(:conditions => {:active => true})
+ ::Author.should_receive(:where).with({:publisher => true})
semantic_form_for(@new_post) do |builder|
concat(builder.input(:author, :as => :select, :find_options => {:conditions => {:publisher => true}}))
@@ -316,11 +317,11 @@
it 'should have a multi-select select' do
output_buffer.should have_tag('form li select[@multiple="multiple"]')
end
-
+
it 'should append [] to the name attribute for multiple select' do
output_buffer.should have_tag('form li select[@multiple="multiple"][@name="author[post_ids][]"]')
end
-
+
it 'should have a select option for each Post' do
output_buffer.should have_tag('form li select option', :count => ::Post.all.size)
::Post.all.each do |post|
@@ -535,7 +536,7 @@
context "when required" do
it "should add the required attribute to the select's html options" do
- with_config :use_required_attribute, true do
+ with_config :use_required_attribute, true do
concat(semantic_form_for(@new_post) do |builder|
concat(builder.input(:author, :as => :select, :required => true))
end)
View
41 spec/spec_helper.rb
@@ -67,7 +67,7 @@ def active_model_length_validator(attributes, options = {})
def active_model_inclusion_validator(attributes, options = {})
active_model_validator(:inclusion, attributes, options)
end
-
+
def active_model_numericality_validator(attributes, options = {})
active_model_validator(:numericality, attributes, options)
end
@@ -93,7 +93,7 @@ def id
def persisted?
end
end
-
+
module ::Namespaced
class Post
extend ActiveModel::Naming if defined?(ActiveModel::Naming)
@@ -106,18 +106,18 @@ def persisted?
end
end
end
-
+
class ::Author
extend ActiveModel::Naming if defined?(ActiveModel::Naming)
include ActiveModel::Conversion if defined?(ActiveModel::Conversion)
def to_label
end
-
+
def persisted?
end
end
-
+
class ::HashBackedAuthor < Hash
extend ActiveModel::Naming if defined?(ActiveModel::Naming)
include ActiveModel::Conversion if defined?(ActiveModel::Conversion)
@@ -126,34 +126,34 @@ def name
'hash backed author'
end
end
-
+
class ::Continent
extend ActiveModel::Naming if defined?(ActiveModel::Naming)
include ActiveModel::Conversion if defined?(ActiveModel::Conversion)
end
-
+
class ::PostModel
extend ActiveModel::Naming if defined?(ActiveModel::Naming)
include ActiveModel::Conversion if defined?(ActiveModel::Conversion)
end
-
+
def _routes
url_helpers = mock('url_helpers')
url_helpers.stub!(:hash_for_posts_path).and_return({})
url_helpers.stub!(:hash_for_post_path).and_return({})
url_helpers.stub!(:hash_for_post_models_path).and_return({})
url_helpers.stub!(:hash_for_authors_path).and_return({})
-
- mock('_routes',
+
+ mock('_routes',
:url_helpers => url_helpers,
:url_for => "/mock/path"
)
end
-
+
def controller
mock('controller', :controller_path= => '', :params => {})
end
-
+
def default_url_options
{}
end
@@ -171,7 +171,7 @@ def new_post_path(*args); "/posts/new"; end
def author_path(*args); "/authors/1"; end
def authors_path(*args); "/authors"; end
def new_author_path(*args); "/authors/new"; end
-
+
@fred = ::Author.new
@fred.stub!(:class).and_return(::Author)
@fred.stub!(:to_label).and_return('Fred Smith')
@@ -212,6 +212,7 @@ def new_author_path(*args); "/authors/new"; end
@james.stub!(:name).and_return('James')
+ ::Author.stub!(:scoped).and_return(::Author)
::Author.stub!(:find).and_return([@fred, @bob])
::Author.stub!(:all).and_return([@fred, @bob])
::Author.stub!(:where).and_return([@fred, @bob])
@@ -223,7 +224,7 @@ def new_author_path(*args); "/authors/new"; end
::Author.stub!(:persisted?).and_return(nil)
@hash_backed_author = HashBackedAuthor.new
-
+
# Sometimes we need a mock @post object and some Authors for belongs_to
@new_post = mock('post')
@new_post.stub!(:class).and_return(::Post)
@@ -240,7 +241,7 @@ def new_author_path(*args); "/authors/new"; end
@new_post.stub!(:to_key).and_return(nil)
@new_post.stub!(:to_model).and_return(@new_post)
@new_post.stub!(:persisted?).and_return(nil)
-
+
@freds_post = mock('post')
@freds_post.stub!(:to_ary)
@freds_post.stub!(:class).and_return(::Post)
@@ -258,6 +259,7 @@ def new_author_path(*args); "/authors/new"; end
@fred.stub!(:posts).and_return([@freds_post])
@fred.stub!(:post_ids).and_return([@freds_post.id])
+ ::Post.stub!(:scoped).and_return(::Post)
::Post.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
::Post.stub!(:human_name).and_return('Post')
::Post.stub!(:reflect_on_all_validations).and_return([])
@@ -291,7 +293,6 @@ def new_author_path(*args); "/authors/new"; end
::Post.stub!(:persisted?).and_return(nil)
::Post.stub!(:to_ary)
-
::MongoPost.stub!(:human_attribute_name).and_return { |column_name| column_name.humanize }
::MongoPost.stub!(:human_name).and_return('MongoPost')
::MongoPost.stub!(:associations).and_return do |column_name|
@@ -306,14 +307,14 @@ def new_author_path(*args); "/authors/new"; end
::MongoPost.stub!(:to_key).and_return(nil)
::MongoPost.stub!(:persisted?).and_return(nil)
::MongoPost.stub!(:to_ary)
- ::MongoPost.stub!(:model_name).and_return( mock(:model_name_mock, :singular => "post", :plural => "posts", :param_key => "post", :route_key => "posts") )
+ ::MongoPost.stub!(:model_name).and_return( mock(:model_name_mock, :singular => "post", :plural => "posts", :param_key => "post", :route_key => "posts") )
@new_mm_post = mock('mm_post')
@new_mm_post.stub!(:class).and_return(::MongoPost)
@new_mm_post.stub!(:id).and_return(nil)
@new_mm_post.stub!(:new_record?).and_return(true)
@new_mm_post.stub!(:errors).and_return(mock('errors', :[] => nil))
- @new_mm_post.stub!(:title).and_return("Hello World")
+ @new_mm_post.stub!(:title).and_return("Hello World")
@new_mm_post.stub!(:sub_posts).and_return([]) #TODO should be a mock with methods for adding sub posts
@new_mm_post.stub!(:to_key).and_return(nil)
@new_mm_post.stub!(:to_model).and_return(@new_mm_post)
@@ -384,11 +385,11 @@ def self.included(base)
def protect_against_forgery?
false
end
-
+
def _helpers
FakeHelpersModule
end
-
+
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.