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
Ruby Class Instance Variables and Inheritance
Rspec Stubbing Method for Only Specific Arguments
Check If String Contains Any Substring in an Array in Ruby
Ruby Convert String to Method Name
How to Get an Empty Temporary Directory in Ruby on Rails
Error Running 'Requirements_Osx_Brew_Libs_Install...' on MAC 10.7
Is Time.Zone.Now.To_Date Equivalent to Date.Today
Differencebetween "Rails S" and "Bundle Exec Rails S"
Navigate to Ruby Function Definition in VS Code
Ruby Get Time in Given Timezone
Routing Error - Uninitialized Constant
How to Make a Gemset in Rvm the Default
How to Get a List of Files That Have Been 'Required' in Ruby