2016-05-15 5 views
0

私は、次のものを入力できるフォームを作成しようとしています。外部キー。名前をフォームに入力しますが、外部キーとしてIDを保存します。

私はこれを行うさまざまな方法を見つけましたが、すべて大きな欠点があります。 Aのためのコントローラは、このように見えますが

<%= form_for(@a) do |f| %> 
    ... 
    <div class="field"> 
    <%= f.label :b %><br> 
    <%= f.text_field :b %> 
    </div> 
    ... 
<% end %> 

: は、たとえば:私は2つのモデルAとBがあります。

class A < ActiveRecord::Base 
    belongs_to :b 
    validates :b_id, presence: true, inclusion: {in: B.all.map(&:id)} 
end 

class B < ActiveRecord::Base 

end 

を_form.html.erbは、1つの文字列を入力することができます。このフィールドを使用しています:

class AController < ApplicationController 
    ... 
    before_action :get_a_id, only: [:create, :update] 
    ... 

    private 

    def page_params 
     params.require(:a).permit(:name, :b_id, :content) 
    end 

    def get_a_id 
     b_name = params[:a][:b] 
     b = B.find_by(name: b_name) 
     b_id = b.id unless b.nil? 
     params[:a][:b_id] = b_id 
    end 

end 

これは、テキストフィールドに入力された:名前がデータベース内に見つかった場合はどういうわけか機能します。見つからない場合は、検証エラーが表示されますが、text_fieldはハイライトされておらず、(以前に入力された文字列を含む代わりに)空です。 これは、フィールドには名前の代わりにBのオブジェクトが含まれている必要があり、間違った文字列の場合には存在しないためだと思います。 このように操作するのは良い考えではないと思います。

これを実現する良い方法はありますか?私はドロップダウンを望んでいません。なぜなら、そこには多くの価値があるからです。もちろん、次のステップは何らかの自動補完を実装することですが、ここでは数えません。

理論的には、text_fieldを新しいB-objectに関連付ける方法がありますが、:nameを表示するだけです。コントローラは、その名前のデータベースオブジェクトを見つけようとし、プレースホルダをそのオブジェクトに置き換えようとする可能性があります。適切なオブジェクトが見つからない場合、検証は失敗しますが、値は引き続き表示されます(もちろん、検証を変更する必要があります)。

いい方法でこのようなことを達成する方法はありがたいです。不明な点があれば教えてください。

EDIT:
私が実際に達成したいこと:

フォームフィールドの文字列を入力することができます。この文字列は、この文字列をオブジェクトのID(B)に変換する検索が実行されるコントローラに渡され、外部キーとして使用できます。クラスAのオブジェクトが保存されると、バリデーターはIDが設定され、存在するかどうかを確認する必要があります。検証が失敗した場合は、フィールド(文字列付き)を強調表示し、エラーメッセージを表示する必要があります。

主な問題は、名前の文字列がモデルにないことです。ちょうどイドです。したがって、idが検証された場合(適切なアプローチは何か)、エラーメッセージは文字列として名前を含むフィールドに関連付けられません。

+1

オブジェクトbの名前を示唆するためにjquery [autocomplete](https://jqueryui.com/autocomplete/)を使うことができ、ユーザーは結果から選択できます – Dawcars

+0

Thanks @Dawcars、それはちょっとしたステップですアップ。主な問題は、そのオブジェクトのIDを格納する際に名前を入力し、フォームに関連付けられた素晴らしいモデル検証を維持する方法です。 – Klumbe

答えて

1

更新:全画像を取得した後:

仮想属性が必要です。次に、@a.set_b_name=を実行すると、ルックアップが実行され、名前が適用されます。または、名前をインスタンスvarに格納し、バリデーションを使用できます。 より詳細な情報のため、これらのリンク:)

を参照してください古い答えは:

?そして、あなたは新しいを作るiebnil Bが、見つからない場合データベースにない 'b'オブジェクト。 b = B.new(name: params[:name])

+0

ありがとう、しかしそれは私の問題を解決しません(私は前にそれを試しました)。検証に誤りがあると、エラーメッセージが表示されますが、フィールドは強調表示されず、入力されたテキストは消えます。これは、フィールド自体が名前の文字列ではなく、タイプbのオブジェクトに関連付けられているためです。私はtypoを修正し、_form.htm.erbを周囲のタグで拡張しました。 – Klumbe

+1

OK、この場合はクラスAで仮想属性を使用できます:def b_name =(name)とdef b_nameを追加し、b_nameに検証を追加します - このレールのキャストを参照してくださいhttp://railscasts.com/episodes/167-more-on -virtual-attributes?view = asciicastまたはこのヒントについてはhttps://stackoverflow.com/questions/20729962/rails-looking-up-foreign-key-id-using-virtual-attribute-failing質問を参照してください。 – court3nay

+0

ありがとう@ court3nay!それがまさに私がここに必要なものです。私は今コントローラからこの厄介なコールバックを削除することができ、すべてがきれいで予測可能です。検証が失敗した場合、状態を保持するためにインスタンス変数を使用します。その名前を含む移行を書いていないので、その名前は保管されません。私はそれを受け入れることができるようにあなたの答えを変更するのが好きですか? – Klumbe

関連する問題