My app includes a State model that has a country field. Using SimpleForm to build the new and edit forms causes ActionView::Template::Error: undefined method `country_select'.
My Gemfile does not include the country_select gem. It appears that SimpleForm is including that gem into my project or at least behaving as though that gem is expected. I do not get this error when standard Rails form helpers are used.
Am not sure why country_select is included in any way in a gem that really has nothing to do with that specific use case. However, accepting that it is appropriate within SimpleForm, shouldn't it be possible for the end user of SimpleForm to optionally exclude the country_select gem and any built in support? Or at the very least shouldn't there be a warning in the README? I have not had the opportunity to poke around on the SimpleForm code to understand how country_select enters the logic, so cannot offer any suggestions on how to make it's use optional. However, if a warning in the README is more appropriate, I would be happy to generate a pull request.
I think my work around will be to use "pais" for my country field. Have not tried this but a quick read of the country_select gem code does not show any use of that term for "country".
From schema.rb
create_table "states", force: :cascade do |t|
t.string "name"
t.string "abbreviation"
t.string "country"
#...
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
The actions new and edit render _form:
<%= simple_form_for(@state) do |f| %>
<%= render partial: 'shared/error_messages', locals: { model: @state } %>
<div class="form-inputs">
<%= f.input :name %>
<%= f.input :abbreviation %>
<%= f.input :country %> # <== line 13 in the real form
<% #... %>
</div>
<div class="form-actions">
<%= f.button yield(:button_text) %>
</div>
<% end %>
Testing or following the new/edit path for a state yields this error:
StatesControllerTest#test_should_get_edit:
ActionView::Template::Error: undefined method `country_select' for #<SimpleForm::FormBuilder:0x007f28a9a81cf8>
app/views/states/_form.html.erb:13:in `block in _app_views_states__form_html_erb__1257389201885898929_69906310081500'
app/views/states/_form.html.erb:1:in `_app_views_states__form_html_erb__1257389201885898929_69906310081500'
app/views/states/edit.html.erb:7:in `_app_views_states_edit_html_erb__1169936360611348705_69906310063980'
test/controllers/states_controller_test.rb:34:in `block in <class:StatesControllerTest>'
The test generated with rails g scaffold State ... :
require 'test_helper'
class StatesControllerTest < ActionController::TestCase
setup do
@state = states(:tx)
sign_in users(:testadmin)
end
test "should get new" do
get :new
assert_response :success
end
test "should get edit" do
get :edit, id: @state
assert_response :success
end
end
states.yml
tx:
name: Texas
abbreviation: TX
country: USA
states_controller.rb:
class StatesController < ApplicationController
before_action :set_state, only: [:show, :edit, :update, :destroy]
def new
@state = State.new
end
def edit
end
#...
private
def set_state
@state = State.find(params[:id])
end
def state_params
params.require(:state).permit(:name, :abbreviation, :country)
end
end
state.rb
class State < ActiveRecord::Base
has_many :addresses, inverse_of: :state
before_destroy :detach_addresses
scope :null, -> { where(name: 'None') }
scope :not_null, -> { where.not(name: 'None') }
def self.null_id
@null_id ||= self.null.first.id
end
private
def detach_addresses
null_state_id = self.class.null_id
addresses.update_all(state_id: null_state_id)
end
end
Gemfile
source 'https://rubygems.org'
gem 'rails', '4.2.6'
gem 'pg', '~> 0.15'
gem 'bootstrap-sass'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'
gem 'therubyracer', :platform=>:ruby
gem 'simple_form'
gem 'ransack'
gem 'kaminari'
# Authorization & Authentication
gem 'devise'
gem 'pundit'
gem 'bcrypt', '~> 3.1.7'
# Static asset service
gem 'high_voltage'
group :development, :test do
gem 'pry'
gem 'pry-byebug'
end
group :development do
gem 'web-console', '~> 2.0'
gem 'spring'
gem 'better_errors'
gem 'quiet_assets'
gem 'rails_layout'
end
group :test do
gem 'capybara'
gem 'minitest-reporters'
gem 'mini_backtrace'
gem 'guard'
gem 'guard-minitest'
gem 'test_after_commit'
end
group :production do
gem 'thin'
end
The README actually _does_ have a section on country_select here.
Without setting up a full test to reproduce, I would assert you are hitting this due to using a very implicit input call in your view (just giving a field and essentially asking simple_form to sniff out the type, etc.)
You can try two things:
1) As the REAME states, you can disable the country input type being used by changing it to a basic string type.
(in your simple_form initializer)
config.input_mappings = { /country/ => :string }
2) you can explicitly set the type
<%= f.input :country, as: :text %>
Thank you for the issue. @colinross' answer is correct. It doesn't require you to use country_select but if you have a field with the name :country it will try to use. If you don't want that behavior just do what the README say.
Most helpful comment
The README actually _does_ have a section on country_select here.
Without setting up a full test to reproduce, I would assert you are hitting this due to using a very implicit
inputcall in your view (just giving a field and essentially asking simple_form to sniff out the type, etc.)You can try two things:
1) As the REAME states, you can disable the country input type being used by changing it to a basic string type.
(in your simple_form initializer)
config.input_mappings = { /country/ => :string }2) you can explicitly set the type
<%= f.input :country, as: :text %>