How to load a selection list into the method new of a controller?

31 views
Skip to first unread message

LuisRuby

unread,
May 27, 2012, 11:37:14 PM5/27/12
to rubyonra...@googlegroups.com
Hi friends!
I'm relatively new with Rails and I'm struggling for a long time with this problem (it should have a pattern solution but until now I didn't find it): I have the following models: Institution, City, State and Country.

class Country < ActiveRecord::Base
  has_many :states
  has_many :cities, :through => :states
end
# == Schema Information
# Table name: countries
#  id         :integer         not null, primary key
#  sigla      :string(2)       not null
#  nome       :string(30)      not null

class State < ActiveRecord::Base
  has_many   :cities
  has_many   :institutions, :through => :cities
  belongs_to :country
end
# == Schema Information
# Table name: states
#  id         :integer         not null, primary key
#  country_id :integer     not null
#  sigla      :string(2)      not null
#  nome       :string(40)  not null

class City < ActiveRecord::Base
  has_many :institutions
  belongs_to :country
  belongs_to :state
end
# == Schema Information
# Table name: cities
#  id          :integer         not null, primary key
#  country_id  :integer         not null
#  state_id    :integer         not null
#  nome        :string(40)      not null

class Institution < ActiveRecord::Base
  belongs_to :city
end
# == Schema Information
# Table name: institutions
#  id                 :integer         not null, primary key
#  city_id            :integer

The table states is pre-loaded with all Brazil's states (seed):

State.create!(country_id: Country.find(:first, conditions: "sigla = 'ZZ'").id, nome: 'desconhecido', sigla: 'ZZ')
State.create!(country_id: Country.find(:first, conditions: "sigla = 'BR'").id, nome: 'Distrito Federal', sigla: 'DF')
State.create!(country_id: Country.find(:first, conditions: "sigla = 'BR'").id, nome: 'Acre', sigla: 'AC') ... and so on...
City.create!(country_id: Country.find(:first, conditions: "sigla = 'BR'").id,
             state_id: State.find(:first, conditions: "nome = 'desconhecido'").id,
             nome: 'desconhecida')
City.create!(country_id: Country.find(:first, conditions: "sigla = 'BR'").id,
             state_id: State.find(:first, conditions: "nome = 'Paraná'").id,
             nome: 'Cianorte')
City.create!(country_id: Country.find(:first, conditions: "sigla = 'BR'").id,
             state_id: State.find(:first, conditions: "nome = 'São Paulo'").id,
             nome: 'Campinas') ... and so on...

 When I create a new institution, I have to select a city from a drop-down list. But I need to constrain this list with the state the cities belong to. So I tried this way:

routes.rb:
Application.routes.draw do
  get "states/index"
  resources :institutions do
    post 'selstate'
  end
  resources :cities
  resources :states, only: :index

rake routes:
          states_index GET    /states/index(.:format)                                      states#index
institution_selstate POST   /institutions/:institution_id/selstate(.:format)        institutions#selstate
             institutions GET    /institutions(.:format)                                         institutions#index
                            POST   /institutions(.:format)                                         institutions#create
       new_institution GET    /institutions/new(.:format)                                  institutions#new

Institution new template:
<%= form_for(@institution) do |f| %>
  <fieldset>
  <legend>Cidade onde se localiza a instituição</legend>
    <div class="field">
      Estado selecionado:
      <%= @estado_selecionado %>
      <%= link_to "Selecionar estado...", states_path %><br />
      <%= f.label :cidade %>
      <%= f.collection_select :city_id, @cities, :id, :nome, include_blank: true %>
      <!--%#= link_to "Incluir nova cidade", new_city_path %--> (to be included later)
    </div>
<% end %>
  </fieldset>

State index template:
<h3>Selecione um estado</h3>
<table>
  <% @states.each do |s| %>
    <tr>
      <td><%= s.sigla %></td>
      <td><%= s.nome %></td>
      <td><%= button_to 'Selecionar', institution_selstate_path( s ) %></td>
    </tr>
  <% end %>
</table>

class StatesController < ApplicationController
  def index
    @states = State.where('nome != ?', 'desconhecido').order(:nome)
  end

class InstitutionsController < ApplicationController
  def new
    @institution = Institution.new
    if session[:state_id].nil?
      session[:state_id] = State.find_by_sigla('ZZ').id
    end
    @estado_selecionado = State.find(session[:state_id]).nome
    if @estado_selecionado == 'desconhecido'
      @cities = City.all
    else
      @cities = City.where('state_id = ?', session[:state_id]).order(:nome)
    end
    respond_to do |format| ...
    end
  end

  def create
    @institution = Institution.new(params[:institution])
    respond_to do |format|
      if @institution.save ...
    end

  def selstate
    session[:state_id] = params[:id]
    redirect_to new_institution_path
  end
 end

As you can see, after select the state, I return to the Institution new action. My hope was to have a state selected and the cities list constrained to those pertaining to that state. But nothing happens. I receive the same screen before the state selection. I have many similar situations in my system... all waiting for this solution  :-) .
Is my approach correct?
Any help will be very appreciated. Sorry my bad english!
Thanks in advance!

Luis

Colin Law

unread,
May 28, 2012, 2:27:39 AM5/28/12
to rubyonra...@googlegroups.com
That is not right, a cities country is accessible through the state
via @city.state.country.

>   belongs_to :state
> end
> # == Schema Information
> # Table name: cities
> #  id          :integer         not null, primary key
> #  country_id  :integer         not null

Above is not needed.

I have not even read the rest, you have provided much too much
information. If you still have a problem then simplify it down to to
the smallest amount of code that demonstrates it and post that.

Colin

LuisRuby

unread,
May 28, 2012, 8:58:06 AM5/28/12
to rubyonra...@googlegroups.com
Thank you for your fast reply!
Yes, I agree it isn't necessary to put a direct relation to country inside the city model. But I did it because sometimes the user will not know to which state a new city belongs to, and at least he will know the country.

Luis

Em segunda-feira, 28 de maio de 2012 03h27min39s UTC-3, Colin Law escreveu:

Colin Law

unread,
May 28, 2012, 3:49:01 PM5/28/12
to rubyonra...@googlegroups.com
On 28 May 2012 13:58, LuisRuby <alfam...@gmail.com> wrote:
> Thank you for your fast reply!
> Yes, I agree it isn't necessary to put a direct relation to country inside
> the city model. But I did it because sometimes the user will not know to
> which state a new city belongs to, and at least he will know the country.

With it in you could get into a situation where @city.country is not
the same as @city.state.country. Also note that @country.cities will
only include those accessed via state.

Please don't top post, it makes it difficult to follow the thread.
Insert you reply at appropriate points in the previous message.
Thanks.

Colin
> --
> You received this message because you are subscribed to the Google Groups
> "Ruby on Rails: Talk" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/rubyonrails-talk/-/OFqhnkPSj8gJ.
>
> To post to this group, send email to rubyonra...@googlegroups.com.
> To unsubscribe from this group, send email to
> rubyonrails-ta...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/rubyonrails-talk?hl=en.

LuisRuby

unread,
May 28, 2012, 6:31:07 PM5/28/12
to rubyonra...@googlegroups.com

Hmmmm, I didn't think in this situation... you are right. I will exclude country_id from de city model.
Well. Filtering my models to simplify the explanation of my problem, I end up with these:


class State < ActiveRecord::Base
  has_many   :cities
  has_many   :institutions, :through => :cities
  belongs_to :country
end

class City < ActiveRecord::Base
  has_many :institutions
  belongs_to :state
end


class Institution < ActiveRecord::Base
  belongs_to :city
end

The table states is pre-loaded with all Brazil's states (seed):

State.create!(country_id: Country.find(:first, conditions: "sigla = 'ZZ'").id, nome: 'desconhecido', sigla: 'ZZ')
State.create!(country_id: Country.find(:first, conditions: "sigla = 'BR'").id, nome: 'Distrito Federal', sigla: 'DF')
State.create!(country_id: Country.find(:first, conditions: "sigla = 'BR'").id, nome: 'Acre', sigla: 'AC') ... and so on...
City.create!(state_id: State.find(:first, conditions: "nome = 'desconhecido'").id, nome: 'desconhecida')
City.create!(state_id: State.find(:first, conditions: "nome = 'Paraná'").id, nome: 'Cianorte')
City.create!(state_id: State.find(:first, conditions: "nome = 'São Paulo'").id, nome: 'Campinas') ... and so on...


 When I create a new institution, I have to select a city from a drop-down list. But I need to constrain this list with the state the cities belong to. So I tried this way:

routes.rb:
Application.routes.draw do
  get 'states/index'
  resources :institutions do
    post 'selstate'
  end
  resources :cities

rake routes:
          states_index GET    /states/index(.:format)       
                               states#index
institution_selstate POST   /institutions/:institution_id/selstate(.:format)        institutions#selstate
             institutions GET    /institutions(.:format)                                         institutions#index
                            POST   /institutions(.:format)                                         institutions#create
       new_institution GET    /institutions/new(.:format)                                  institutions#new

Institution new template:
<%= form_for(@institution) do |f| %>
    <div class="field">
      Estado selecionado: <%= @estado_selecionado %>
      <%= link_to "Selecionar estado...", states_path %><br />
      <%= f.label :cidade %>
      <%= f.collection_select :city_id, @cities, :id, :nome, include_blank: true %>
    </div>
<% end %>


State index template:
<h3>Selecione um estado</h3>
<table>
  <% @states.each do |s| %>
    <tr>
      <td><%= s.sigla %></td>
      <td><%= s.nome %></td>
      <td><%= button_to 'Selecionar', institution_selstate_path( s ) %></td>
    </tr>
  <% end %>
</table>

class StatesController < ApplicationController
  def index
    @states = State.all
As you can see, after select the state, I return to the Institution new action. My hope was to have a state selected and the cities list constrained to those pertaining to that state. But nothing happens. I receive the same screen before the state selection. Is my approach correct?
 
Thanks!
Luis
Reply all
Reply to author
Forward
0 new messages