README.md in token_field-1.1.0 vs README.md in token_field-2.0.0
- old
+ new
@@ -1,24 +1,36 @@
# TokenField
-This gem add helper for form_for to Ruby on Rails 3.+
+[![Build Status](https://travis-ci.org/mirrec/token_field.svg?branch=master)](https://travis-ci.org/mirrec/token_field)
+
+This gem add helper for form_for to Ruby on Rails
form_for helper for token input with jquery token input plugin
for has_many and belongs_to association
http://railscasts.com/episodes/258-token-fields
+
http://loopj.com/jquery-tokeninput/
+
https://github.com/foohey/jquery-tokeninput-rails
+Supported Ruby on Rails versions:
+* ~> 3.2.1
+* ~> 4.0.1
+* ~> 4.1.1
+* ~> 4.2.1
+
helper will render standard text field input with javascript.
javascript will change standard input to token field input
## Installation
Add this line to your application's Gemfile:
- gem "jquery-tokeninput-rails" # dependency
- gem "token_field"
+```ruby
+gem 'jquery-tokeninput-rails' # dependency
+gem 'token_field'
+```
And then execute:
$ bundle
@@ -36,172 +48,218 @@
usage for tree
we have a model Category like this
- class Category < ActiveRecord::Base
- attr_accessible :name, :parent_id
- has_many :categories, :foreign_key => :parent_id
- belongs_to :parent, :foreign_key => :parent_id, :class_name => "Category"
+```ruby
+class Category < ActiveRecord::Base
+ attr_accessible :name, :parent_id
- # method for converting array of categories to array of hashes in format that token input accepts
- def self.token_json(items)
- items.map{|i| {:id => i.id, :name => i.name} }
- end
- end
+ has_many :categories, :foreign_key => :parent_id
+ belongs_to :parent, :foreign_key => :parent_id, :class_name => "Category"
+ # format that token input use
+ def to_token
+ {:id => id, :name => name}
+ end
+end
+```
+
we have action for responding for token input ajax calls, simple autocomplete
- class CategoriesController < ApplicationController
+```ruby
+class CategoriesController < ApplicationController
- # action for autocomplete
- def token
- @categories = Category.where("categories.name like ?", "%#{params[:q]}%")
- respond_to do |format|
- format.json { render :json => Category.token_json(@categories) }
- end
- end
+ # action for autocomplete
+ def token
+ categories = Category.where("categories.name like ?", "%#{params[:q]}%")
- # rest of the class
- end
+ respond_to do |format|
+ format.json { render :json => categories.map(&:to_token) }
+ end
+ end
+ # rest of the class
+end
+```
+
in routes we have route for token ajax call
- MyApplication::Application.routes.draw do
- resources :categories do
- collection do
- get :token # route for token -> token_categories_path
- end
- end
+```ruby
+MyApplication::Application.routes.draw do
+ resources :categories do
+ collection do
+ get :token # route for token -> token_categories_path
end
+ end
+end
+```
then in view we call token_field with param :model => :category
- <%= form_for @category do |f| %>
- <%= f.token_field :parent_id, :model => :category, :token_url => token_categories_path %>
- <% end %>
+```erb
+<%= form_for @category do |f| %>
+ <%= f.token_field :parent_id, :model => :category, :token_url => token_categories_path %>
+<% end %>
+```
in case model is in namespace for example MyApp you should use :model like this
- <%= form_for @category do |f| %>
- <%= f.token_field :parent_id, :model => "MyApp::Category", :token_url => token_categories_path %>
- <% end %>
+```erb
+<%= form_for @category do |f| %>
+ <%= f.token_field :parent_id, :model => "MyApp::Category", :token_url => token_categories_path %>
+<% end %>
+```
if you need dynamically evaluated url of token input, you can pass inline javascript function to `:token_url` options but with `:token_url_is_function` set to `true`
- <%= form_for @category do |f| %>
- <%= f.token_field :parent_id, :model => :category, :token_url => "function(){ return '/hello' }", :token_url_is_function => true %>
- <% end %>
+```erb
+<%= form_for @category do |f| %>
+ <%= f.token_field :parent_id, :model => :category, :token_url => "function(){ return '/hello' }", :token_url_is_function => true %>
+<% end %>
+```
also own separate function are supported
- <%= form_for @category do |f| %>
- <%= f.token_field :parent_id, :model => :category, :token_url => "myDynamicUrl", :token_url_is_function => true %>
- <% end %>
+```erb
+<%= form_for @category do |f| %>
+ <%= f.token_field :parent_id, :model => :category, :token_url => "myDynamicUrl", :token_url_is_function => true %>
+<% end %>
- <script type="text/javascript">
- function myDynamicUrl() {
- return "/my-url/";
- }
- </script>
+<script type="text/javascript">
+ function myDynamicUrl() {
+ return "/my-url/";
+ }
+</script>
+```
if there would be model Parent, we can omit :model parameter.
for example in Product model like this
- class Product < ActiveRecord::Base
- belongs_to :category
- end
+```ruby
+class Product < ActiveRecord::Base
+ belongs_to :category
+end
+```
we can use this code in view
- <%= form_for @product do |f| %>
- <%= f.token_field :category_id, :token_url => token_categories_path %>
- <% end %>
+```erb
+<%= form_for @product do |f| %>
+ <%= f.token_field :category_id, :token_url => token_categories_path %>
+<% end %>
+```
helper will allow you to enter only one element.
### has_many with token_input
We can use token_input also for mapping categories to product
we will use ActiveRecord method category_ids which be default return array of ids from association
in model we have to change category_ids= method like this
- class Product < ActiveRecord::Base
- has_many :product_has_categories
- has_many :categories, :through => :product_has_categories
+```ruby
+class Product < ActiveRecord::Base
+ has_many :product_has_categories
+ has_many :categories, :through => :product_has_categories
- alias_method :category_ids_old=, :category_ids=
- def category_ids=(ids)
- ids = ids.split(",").map(&:to_i) if ids.is_a?(String)
- self.category_ids_old=ids
- end
+ alias_method :category_ids_old=, :category_ids=
+ def category_ids=(ids)
+ ids = ids.split(",").map(&:to_i) if ids.is_a?(String)
+ self.category_ids_old=ids
+ end
- # rest of the class...
- end
+ # rest of the class...
+end
+```
in view you will use attribute category_ids. token input will expected more than one category.
so you can enter more than one category.
- <%= form_for @product do |f| %>
- <%= f.token_field :category_ids, :token_url => token_categories_path %>
- <% end %>
+```erb
+<%= form_for @product do |f| %>
+ <%= f.token_field :category_ids, :token_url => token_categories_path %>
+<% end %>
+```
if you want to use multiple token inputs on page, and id of element would be the same, you can user option :append_to_id.
- <%= form_for @product do |f| %>
- <%= f.token_field :category_ids, :token_url => token_categories_path, :append_to_id => :id %>
- <% end %>
+```erb
+<%= form_for @product do |f| %>
+ <%= f.token_field :category_ids, :token_url => token_categories_path, :append_to_id => :id %>
+<% end %>
+```
if @product.id is present and for example "3" it will use this id and generate id of html input like this "product_categories_ids_3"
if @product.id is nil id of html input will be "product_categories_ids"
other value for :append_id option will be used like this
- <%= form_for @product do |f| %>
- <%= f.token_field :category_ids, :token_url => token_categories_path, :append_to_id => 5 %>
- <% end %>
+```erb
+<%= form_for @product do |f| %>
+ <%= f.token_field :category_ids, :token_url => token_categories_path, :append_to_id => 5 %>
+<% end %>
+```
id of html input will be "product_categories_ids_5"
### SimpleForm support
if you use simple_form in your project, TokenInput field will be loaded.
you can use it in view like this
- <%= simple_form_for(@item) do |f| %>
- <%= f.input :category_id, :as => :token, :token_url => token_categories_path %>
- <% end %>
+```erb
+<%= simple_form_for(@item) do |f| %>
+ <%= f.input :category_id, :as => :token, :token_url => token_categories_path %>
+<% end %>
+```
all options for token_field helper can be used in simple form helper as well.
+## Updating from 1.x to 2.0
+
+* Add `#to_token` method to model you are using
+* Remove `.token_json` method, we don't use it anymore
+* require dsl helper for tests (see below)
+
## Testing
add support for helpers in rspec
- RSpec.configure do |config|
- config.include TokenField::Capybara::Dsl
- end
+```ruby
+require 'token_field/capybara/dsl'
+RSpec.configure do |config|
+ config.include TokenField::Capybara::Dsl
+end
+```
+
### test helpers for capybara
filling token input
- fill_in "category_parent_id", :with => new_parent.id # standard input
- fill_in_token "category_parent_id", :with => "wood"
+```ruby
+fill_in "category_parent_id", :with => new_parent.id # standard input
+fill_in_token "category_parent_id", :with => "wood"
+fill_in_token "category_parent_id", :with => "wood", :waiting_call => lambda { sleep(4) }
+```
clearing token input
- clear_token "category_parent_id"
+```ruby
+clear_token "category_parent_id"
+```
project is covered by integration tests. using rspec, capybara and selenium
how to run test
- bundle # install dependency
- rake db:create
- rake db:migrate RAILS_ENV=test
- rspec spec/
-
+```bash
+bundle # install dependency
+rake db:create
+rake db:migrate RAILS_ENV=test
+rspec spec/
+```
## Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
\ No newline at end of file