Rails - Displaying Foreign Key References in a Form

Rails - Displaying Foreign Key References in a form

You are using a text_field for referencing an existing object, a select with Sports as options would be more appropriate here.

This is where it has to be changed:

<div class="field">
<%= f.label :sport %><br />
<%= f.text_field :sport %>
</div>

To:

<div class="field">
<%= f.label :sport %><br />
<%= f.select :sport_id, options_for_select(Sport.all.map{|s|[s.name, s.id]}) %>
</div>

The f.select will generate a select box in HTML, the options will me all the sports in your DB.

Some documentation about it:

  • http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/select
  • http://guides.rubyonrails.org/form_helpers.html#select-boxes-for-dealing-with-models

A cleaner way would be to set a variable @sports in your controller and call it then in your views:

# in controller
def edit
@sports = Sport.scoped
#...

# in edit view
<div class="field">
<%= f.label :sport %><br />
<%= f.select :sport_id, options_for_select(@sports.map{ |s| [s.name, s.id] }) %>
</div>

Additionnal information: If you want to "pre-select" an option for the select, you have to pass it as the second argument of the options_for_select helper:

options_for_select(@sports.map{ |s| [s.name, s.id] }, params[:sport_id])
# this will select by default the option that matches the value of params[:sport_id]

How to set foreign key using value from nested form?

If you have the link value set in contents form AND you have a logic to determine the source from the value of link, then you don't need to set source_id in form OR in the controller.

Best place to set the source_id would be in the model, so that it is always set no matter how you create the content record i.e. from editions form, from console, or from some other controller. You won't have to worry about that in this case.

Having these associations and callbacks in your models should solve your purpose:

class Source
# field :name
# field :domain

has_many :contents

def self.fetch_from_link(link)
match_link_with_domains_and_return_source_record
end
end

class Edition
# field :date
# field :clicks

has_many :contents
accepts_nested_attributes_for :contents
end

class Content
# field :heading
# field :body
# field :link
# field :top_story

belongs_to :source
belongs_to :edition

before_validation :set_source

private

def set_source
# Set source *only* if not already set. You can change `||=` to `=` to set it always.
self.source ||= link && Source.fetch_from_link(link)
end
end

How to use foreign key in model and form builder?

It sounds like you actually want to have

class User < ActiveRecord::Base
belongs_to :location
end

class Location < ActiveRecord::Base
has_many :users
end

This means that a user has a location_id column. If you do things the other way around (user_id column on location) then a given location can only be associated to one user. The rails way is that location_id on users 'points' at the id column in the locations table. If you want it to point at a different column, use the :primary_key option (The :foreign_key option would be if you wanted the column on users to be called something other than location_id)

In terms of the form, you can't do f.select :location - forms don't know how to transfer a complicated object like that. In these cases you want to set the form to control the location_id attribute, i.e.

= f.input :location_id, :collection => Location.all.collect {|c| [c.loc_name, c.id]}

If you go down the route of having the location id column refer to the loc_id column on location, then you'd need to change that to be

= f.input :location_id, :collection => Location.all.collect {|c| [c.loc_name, c.loc_id]}

Personally if you're only just starting out with rails I'd stick to the defaults

registration forms and foreign keys in Rails

Ok, so it turns out this is really simple. You don't need to do any logic in the controller or model. You just do the following in the registration form:

<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>

The above line is just the form_for that creates a form. the scaffold, or in this case, Devise will create this. Remember the do |f| at the end.

<%= devise_error_messages! %>
<%= f.label :Whats_your_goal? %><br />
<%= f.collection_select :user_goal_id, UserGoals.all, :id, :name, { :include_blank => ""}%>

The first line is just the label for the field

The second line is the drop down. f.collection_select tells your form generator that this is going to be a drop down list of options.

:user_goal_id is the name of the field in the users table where I want to record the foreign key of the goal from the user_goals table.

UserGoals.all is the name of database table I want the drop down list to populate from. .all says I want all of the items from that database table

I believe :id, pulls the items by their database ID number or primary key, and :name says give me the name column of the table, as opposed to description, or something.

Finally, { :include_blank => "" } just creates a blank space at the top of the drop down, so there isn't a default selection. You can also put a message between the "" if you want.

I had a hard time finding a simple explanation of this, probably since it's so basic. Hopefully someone else will find this useful.

Enter name in form but save the id as foreign key

Update: after getting the full picture:

You want virtual attributes. Then you can do, @a.set_b_name= and it will do the lookup and apply the name, or you can store the name in an instance var and use validations on it.
See these links for more detailed info :)

  • http://railscasts.com/episodes/167-more-on-virtual-attributes?view=asciicast
  • Rails: Looking up foreign key id using virtual attribute failing

Old answer was:

if B cannot be found, i.e. b.nil?, then you make a new 'b' object that isn't in the database; b = B.new(name: params[:name]).

Ruby on Rails - How to show foreign key values in one model to another

Instead of:

newspaper.language_id

you just need to use:

newspaper.language.name

or, if you aren't sure that every Newspaper belongs to corresponding Language, you could use try method:

newspaper.language.try(:name)

And BTW, to avoid N+1 queries problem, you should include your language association while fetching newspapers in controller, with includes method:

@newspapers = Newspaper.includes(:language).your_other_scopes

This way, you need to generate two SQL queries to fetch both newspapers and each one's associated language. If you didn't use includes, there would be a SQL query generated to fetch each newspaper's language, which would be much less efficient. More info here:
http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

Single Foregn Key references multiple Tables [Rails6]

What you are looking for is Polymorphic Associations. You can add something like,

class Suggestion
...
belongs_to :suggestable, polymorphic: true
...
end

In the database, you'll add two columns to the suggestions table.

t.bigint  :suggestable_id
t.string :suggestable_type

Then you can simply use suggestion.suggestable which will give you the corresponding object of the correct type, without having to manage any of the types or integers yourself.



Related Topics



Leave a reply



Submit