1

関連する 2 つのモデル/テーブルがあります

アプリ/モデル/city.rb
has_many :ビジネス
フィールド: ID、city_name、state_code

アプリ/モデル/business.rb
所属先:都市
フィールド: id、biz_name、address、city_name、state_code、zip

会社の住所を入力する新しいビジネス フォームでは、都道府県や国のドロップダウン選択ボックスを使用するのが一般的です。しかし、都市の場合は数千あるため、機能しません。保存を許可する前に、都市が都市テーブルにリストされていることを確認する方法はありますか? そして、そのフィールドに city_name の代わりに city_id を入れることさえありますか?

4

3 に答える 3

0

回答の提案と私自身のさらなる調査に基づいて、関連するテーブルからフォーム内の多数のオプションを取得する最良の方法についての私の結論です。

オートコンプリートが最適なソリューションのようです。これは通常のテキスト フィールドですが、2 番目の文字を入力すると、最初に見つかった 10 個の一致が取り込まれ、以下にリストされます。文字を追加するたびに、検索が絞り込まれます。私は JavaScript にあまり熟練していないので、提案されたように独自の JS で補完されたプラグインを追加するのではなく、gem、特にrails-jquery-autocompleteを使用して JS コーディングを抽象化することにしました。
手順は次のとおりです。

設定

足場を生成します。

rails generate scaffold City name state
rails generate scaffold Business name address city:references state zip
rake db:migrate

ジェムをインストールします。jQuery-UI のオートコンプリート ウィジェットを使用するので、そのための rails gem もインストールします。

# gemfile
gem 'jquery-ui-rails'
gem 'rails-jquery-autocomplete'

これらを JavaScript およびスタイルシート アセットに追加します。

# app/assets/javascripts/application.js > put these after //= require jquery_ujs
//= require jquery-ui/autocomplete
//= require autocomplete-rails

# app/assets/stylesheets/application.css     
*= require jquery-ui/autocomplete

モデル

最初に関連付けを作成します。

# app/model/city.rb
has_many :businesses

# app/model/business.rb
belongs_to :city

入力した都市が都市テーブルにあることを確認する場合は、検証を追加します。

# app/models/business.rb
validates :city, presence: true

ビジネス テーブルには、都市名ではなく、city_id のフィールドがあります。getter メソッドと setter メソッドを使用して、ビジネス モデル ファイルに仮想属性を作成できます。4歳のRailsCastから入手したので、これを行うにはおそらくもっと最新の方法がありますが、うまくいきます。

#getter method
def city_name
  city.try(:name)
end
#setter method
def city_name=(name)
  self.city = City.find_by(name: name) if name.present?
end

ルート

ここで、gem の魔法が働きます。autocomplete_model_attribute としてフォーマットされたビジネス REST リソースへのルートを追加します。

# config/routes.rb
resources :businesses do
  get 'autocomplete_city_name' on: :collection
end

コントローラ

コントローラーの上部で、クラス名と属性を渡してオートコンプリート アクションを呼び出します。デフォルトでは、オートコンプリートは単語の先頭から始まるテキストと一致します。単語内の任意の場所を検索する場合は、'full' オプションを true に設定します。それ以外の場合は省略します。

# app/controllers/business_controller.rb
autocomplete :city, :name, full: true

ビジネス モデルで city_name 仮想属性を作成したので、それを許可されたパラメーター リストに追加する必要があります。

def business_params
  params.require(:business).permit(:name, :address, :city_id, :state, :zip, :city_name)
end

ビュー

新しいビジネス インスタンスを作成または編集するフォームで、autocomplete_field ヘルパーを使用して、city_id フィールドを city_name 仮想属性に変更します。'data-auto-focus' オプションは、リストの最初の値を自動的に選択します。したくない場合はオフにしてください。

# app/views/businesses/_form.html.erb
<div class="field">
  <%= f.label :city_name %><br>
  <%= f.autocomplete_field :city_name, autocomplete_city_name_businesses_path, 'data-auto-focus' => true %>
</div>

終わり!

于 2015-10-22T05:43:16.027 に答える
0

フィールドにオートコンプリート機能を追加するcity_nameと、問題が解決します。

まず第一に、あなたBusinessとオブジェクトの間の関連付けのため、パラメーターではなくパラメーターCityを返したいと思うでしょう (ヘルパーを使用していると仮定します)。business[city_id]city_nameform_for @business

jQuery を使用している場合は、devbridge jQuery-Autocomplete プラグインを使用できます: https://github.com/devbridge/jQuery-Autocomplete

都市のリストを JSON 形式で返す単純なメソッドを作成します (デフォルトで Gemfile に含まれている jbuilder gem が必要です)。たとえば、次のようになります。

in app/controllers/businesses_controller.rb:

def ac_cities
  @query = params[:query]
  @results = City.where('city_name LIKE ?', "#{@query}%").order(city_name: :asc).limit(10)
  respond_to do |format|
    format.json
  end
end

in app/views/businesses/ac_cities.json.jbuilder:

json.query @query
json.suggestions @results do |result|
  json.value "<div data-id=\"#{result.id}\">#{result.city_name}</div>"
end

devbridge インスタンスを初期化し、city_nameCoffeeScript (または JS) を使用してフィールドに接続します。devbridge プラグインには、非表示のフォーム フィールドonSelectに入力できる機能もあります。business[city_id]たとえば、上記で返された JSON があるとします。

in app/assets/javascripts/businesses.js.coffee:

BusinessCitySelect = (suggestion) ->
  $(this).next('#business_city_id').val(suggestion.value.match(/data-id="(\d+)"/i)[1])
  $(this).val(suggestion.value.replace(new RegExp('<.*?\/?>', 'gi'), ''))

SearchACFormat = (suggestion, cv) ->
  pattern = '(<div.*?>.*?)('+cv+').*?'
  suggestion.value.replace(new RegExp(pattern, 'gi'), '$1<strong>$2<\/strong>')

$("#city_name").devbridgeAutocomplete({
  serviceUrl: "/businesses/ac_cities.json",
  formatResult: SearchACFormat,
  onSelect: BusinessCitySelect,
  noCache: true
})

このSearchACFormatメソッドは、devbridge のformatResult機能を利用して JSON をクリーンアップし、city_name入力フィールド内に適切に表示すると同時にハイライトも提供します。

于 2015-10-12T23:59:38.997 に答える
0

validates_associatedこの状況ではうまくいかないと思います。カスタムvalidateメソッドを作成するだけです。これは、都市がすべて小文字で保存されている場合に機能します。それ以外の場合は、humanize代わりに を使用しdowncaseます。

validate :city_must_exist_with_city_name

def city_must_exist_with_city_name
    if !City.find_by(name: city_name.downcase)
        errors.add(:item_name, "must be a valid city.")
    end
end

編集:これを行うことで、大文字の問題をさらに一歩進めることができます:

if !City.where("lower(name) = ?", city_name.downcase).first
于 2015-10-12T23:52:20.357 に答える