Passing foreign key automatically from view to controller using HABTM models - ruby-on-rails

I have two models, Companies and Employees, with a many-to-many association between them.
class Company < ActiveRecord::Base
has_and_belongs_to_many :employees
end
class Employee < ActiveRecord::Base
has_and_belongs_to_many :companies
end
I have a join table :companies_employees
class CreateCompaniesEmployeesJoin < ActiveRecord::Migration
def change
create_table :companies_employees, :id => false do |t|
t.integer "company_id"
t.integer "employee_id"
end
add_index :companies_employees, ["company_id", "employee_id"]
end
end
I have a Show view for Company, which includes a form_for adding a new Employee, who I want to associate with that Company via the HABTM association:
<%= form_for :employee, :url => employees_path do |f| %>
<p>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</p>
<br>
<p>
<%= f.hidden_field :company_id, :value => #company.id %>
</p>
<p>
<%= f.submit "Save Employee", class: "btn btn-default" %>
</p>
<% end %>
I have a controller for Employee, through which I want to create a new Employee that will be automatically associated with the Company from the Company Show view:
def create
#company = Company.find(params[:company_id])
#employee = Employee.new(employee_params)
#company.employees << #employee
if #employee.save
flash[:success] = "Company Employee Added!"
redirect_to #employee
else
render 'new'
end
end
When I use the form to try to create a new employee, I get an error in EmployeeController -- "Couldn't find Company without an ID"
Seems my view is failing to pass the :company_id on to the create action in the EmployeeController.
I've scoured other posts and nothing seems to be on point. Any suggestions most appreciated!

Ok, the problem seems to be the nested attribute.
Try to change in the EmployeesController#create the first row in:
#company = Company.find(params[:employee][:company_id])
EDIT
Alternatively, and probably more easy, you can also change the form hidden_field like this:
hidden_field_tag(:company_id, #company.id)

Related

How to populate the has_many :through model table

My Models:
class Event < ActiveRecord::Base
belongs_to :organization
has_many :directors
has_many :vips, :through => :directors
end
class Vip < ActiveRecord::Base
belongs_to :organization
has_many :directors
has_many :events, :through => :directors
end
class Director < ActiveRecord::Base
belongs_to :vip
belongs_to :event
end
My New Event form:
<%= form_for [#organization, #event] do |f| %>
<p>
<%= f.label :when %>
<%= f.date_select :when %>
</p>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :vip %>
<%= f.select :vip_id, options_for_select(#organization.vips.all.map {|v| [v.name, v.id]}) %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
And my Events Controller:
def new
#organization = Organization.find(params[:organization_id])
#event = #organization.events.new
#director = Director.new
end
def create
#organization = Organization.find(params[:organization_id])
#event = #organization.events.build(event_params)
if #event.save
redirect_to organization_path(#organization)
else
render 'new'
end
end
So, my Vips are created earlier in the process and sit in the vips table. When I submit the new event form, I get a new entry to my events table just fine. What I want to do is have my directors table be populated with a new entry when I submit the new events form. The directors table would need the event_id of the event I just created, and the vip_id from the select tag in the form.
I thought about adding this to the create action
def create
#director = Director.new
if #event.save
redirect_to organization_path(#organization)
#director.vip_id = #event.vip_id
#director.event_id = #event.id
But that didn't create an entry into the director table. Is there a way to do this that I'm not seeing?
#director.vip_id = #event.vip_id
#director.event_id = #event.id
So, you have these two assignments, #director.event_id = #event.id this one is fine because you just created the event and you have the #event.id.
But, the first one won't work. Looking at your Model associations, #event does not have a vip_id, so you can't call #event.vip_id. You have to go to the vip through the organization, something like:
#event.organization.vips.first.vip_id
or, #event.vips.first.vip_id this would work too as you have :through => :directors association.
These two are the only way I see to get a valid vip_id corresponding to the event. Although, this will only get the first vip_id or you can specify some criteria in a where clause to get a particular vip_id for that event.
If that works for you, good. Otherwise, you may have to re-think your associations among the models.

Rails Associations - Strong Parameters Build

So I have to following models.
class Team < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :players
accepts_nested_attributes_for :players
end
class Player < ActiveRecord::Base
has_many :statistics
has_and_belongs_to_many :teams
end
I wish to build a team that has players, these will be selected by the user. I can do this perfectly in the console by doing to following.
#user = User.find(10)
#team = #user.build_team(name: "MyTeam", points: 0)
#<Team team_id: nil, name: "MyTeam", points: 0, user_id: 10>
#team.players.build(name: "Messi")
#<Player player_id: nil, name: "Messi", role: nil>
#team.save
However I am really struggling passing parameters due to strong params. Here is my view
<%= form_for :team do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %>
<%= f.fields_for :players do |players| %>
<%= players.label :player_name %>
<%= players.text_field :name %>
<% end %>
<div><%= f.submit "Create Team" %></div>
<% end %>
I want to build the team using the team parameters and the players using the player parameters, however I cannot figure out how to get this working in the controller.
class TeamController < ApplicationController
before_action :authenticate_user!
def new
end
def create
#user = User.find(current_user.id)
#team = #user.build_team(team_params) #Just the team paramaters
#team = #team.players.build(player_params)# I want just the player params
#team.save
end
private
# I can add the player param as nested i.e. .permit(:name, :players => [:name])
# but then build_team complains about receiving an array.
def team_params
params.require(:team).permit(:name)
end
end
Any solutions welcome, as are any improvements.
EDIT - ADDED SCHEMA
create_table "players", primary_key: "player_id", force: true do |t|
t.string "name", limit: 50, null: false
t.string "role", limit: 30, null: false
end
create_table "players_teams", id: false, force: true do |t|
t.integer "player_id", null: false
t.integer "team_id", null: false
end
# players_teams is a Composite Primary Key, as instructed in the guides;
# also essential for targeting.
create_table "teams", primary_key: "team_id", force: true do |t|
t.string "name", limit: 200, null: false
t.integer "points", default: 0, null: false
t.integer "user_id", null: false
end
EDIT 2
Since this has not yet been answered I'll add more explanation as to what I am attempting.
The user has one team, I can build the team and the relationship is also built thanks to ActiveRecord. The users team then has many players and players have many teams, when I try to build this relationship the players table never changes, no relationship is created.
I feel I should stress again that the following works perfectly in the rails console
#user = User.find(10)
#team = #user.build_team(name: "MyTeam", points: 0)
#<Team team_id: nil, name: "MyTeam", points: 0, user_id: 10>
#team.players.build(name: "Messi")
#<Player player_id: nil, name: "Messi", role: nil>
#team.save
Team is set to accept nested parameters so I thought this would work.
#team = #user.build_team(team_params)
def team_params
params.require(:team).permit(:name, players_attributes: [:name, :role])
end
I believe this should build the players model and create the relationship however no player is ever inserted and no relationship built.
First make a few changes in the TeamsController as below:
class TeamController < ApplicationController
before_action :authenticate_user!
def new
## Set "#team" and build "players"
#team = current_user.build_team
#team.players.build
end
def create
#team = current_user.build_team(team_params)
if #team.save
## Redirect to teams show page
redirect_to #team, notice: 'Team was successfully created.'
else
## In case of any error while saving the record, renders the new page again
render action: 'new'
end
end
private
# I can add the player param as nested i.e. .permit(:name, :players => [:name])
# but then build_team complains about receiving an array.
def team_params
## Permit players_attributes
params.require(:team).permit(:name, players_attributes: [:id, :name])
end
end
After this, update the view as below:
<%# Changed "form_for :team" to "form_for #team" %>
<%= form_for #team do |f| %>
<%= f.label :name %><br />
<%= f.text_field :name %>
<%= f.fields_for :players do |player| %> <%# Changed "|players|" to "|player|" %>
<%= player.label :name %> <%# Changed "player_name" to "name" and "players" to "player" %>
<%= player.text_field :name %> <%# Changed "players" to "player" %>
<% end %>
<div><%= f.submit "Create Team" %></div>
<% end %>
Set an instance variable #team in new action and build the players for that #team.
Use #team instance variable as an argument for form_for in your view code.
I have also suggested a few tweaks in the create action, so you know if the team is saved or not.
And fixed the team_params method to permit the nested attributes of players.
UPDATE
Using #team as an argument to form_for method is resource-oriented style and much preferred way.
Read this pretty good description about usage of form_for to get a better idea.
You can still implement the required code while using :team but its not preferred way of doing it.
Example using :team:
<%= form_for :team do |f| %>
<%# ... %>
<%= f.fields_for :players, f.object.players.build do |player| %> <%# build the players for the team %>
<%# ... %>
<% end %>
<%# ... f.submit "Create Team" %>
<% end %>
fields_for in your case would iterate over players (#team.players) belonging to a particular team (#team). If there are no players then you won't see any fields for players in the form, which is why you build the players so you at least get some blank fields for players to input which is why when using accepts_nested_attributes_for you need to build the nested attributes. You can build them either at controller level(as shown in above suggested code) or within the form.
Example for "within the form":
<%= form_for #team do |f| %>
<%# ... %>
<%= f.fields_for :players, #team.players.build do |player| %> <%# build the players for #team %>
<%# ... %>
<% end %>
<%# ... f.submit "Create Team" %>
<% end %>
Normally you'd just do the nested attributes at once which will create the players through nested attributes e.g.
def create
#user = User.find(current_user.id)
#team = #user.build_team(team_params)
#team.save
end
def team_params
params.require(:team).permit(:name, :players => [:name])
end
If you're desperate to seperate them you should be able to do something like
def player_params
params.require(:team).permit(:name, :players => [:name])[:team][:players]
end
I.e. you're going to have to filter out just the players parameters
As I was literally going through the same issues this weekend, I would highly recommend using a nested_form.
You can find all the implementation details here: https://github.com/ryanb/nested_form
You are very close with what you had.
Just add the :id field to player_attributes params and it should work for you.
def team_params
params.require(:team).permit(:name, players_attributes: [:id, :name, :role])
end
You may want to check out the cocoon gem. It makes it a lot easier for handling the nested forms and allowing users to add/remove using JS.
If you also want to allow destroying, add a check box for the field _destroy on the player and add the key in players_attributes. Also update the model to allow destroying.
Model:
class Team < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :players
accepts_nested_attributes_for :players, allow_destroy: true
end
Controller:
def team_params
params.require(:team).permit(:name, players_attributes: [:id, :_destroy, :name, :role])
end
View:
<%= f.fields_for :players do |player| %> <%# Changed "|players|" to "|player|" %>
<%= player.label :name %> <%# Changed "player_name" to "name" and "players" to "player" %>
<%= player.text_field :name %> <%# Changed "players" to "player" %>
<%= player.check_box :_destroy %> Delete
<% end %>

Passing Checkbox values to model

I am making a model where users can belong to multiple teams and teams have multiple people.
I have checkboxes but they don't pass the value onto the object.
class User < ActiveRecord::Base
attr_accessible :email, :name
has_many :teams
accepts_nested_attributes_for :teams
end
class Team < ActiveRecord::Base
has_many :users
attr_accessible :name
end
Here is the code in my controller
def create
#users = User.all
#user = User.new
#teams = Team.all
#user.attributes = {:teams => []}.merge(params[:user] || {})
end
Here is the code in my view file
<%= form_for #user, url: {action: "create"} do |f| %>
<%= f.label :teams%>
<% for team in #teams %>
<%= check_box_tag team.name, team.name, false, :teams => team.name%>
<%= team.name -%>
<% end %>
<%= submit_tag "Create User" %>
I am trying to show it into
<%= user.teams.name %>
But the only output is "Team"
Can someone tell me what I am doing wrong?
Actually, you can't do a many-to-many relationship that way... you need to do has_many :through or alternatively has_and_belongs_to_many Nice explanation here...
http://guides.rubyonrails.org/association_basics.html

I can't insert to my database rails

i can't insert to my database whats is my problem?
it's bowling game and i have two tables with name "Player" and "Result"
view
<%= form_for player_new_path(#player) do |f|%>
<div class="text_field">
<p>
<%= f.label "Spelare namn" %>
<%= f.text_field :name %>
</p>
<p>
<%= f.submit "Lägg till en spelare"%>
</p>
</div>
Controller
def create
#player = Player.new(params[:players])
if #player.save
redirect_to players_new_path
else
render :action => "new"
end
end
Not work :/
my model:
class Player < ActiveRecord::Base # attr_accessible :title, :body
belongs_to :result
end
and my migrations:
class CreatePlayers < ActiveRecord::Migration
def change
create_table :players do |t|
t.string "name"
t.references :results
t.timestamps
end
Check your params hash. I bet the key isn't 'players', it's probably 'player'.
#player = Player.new(params[:players]) should probably be #player = Player.new(params[:player]) (You are getting a single player as a param)
Otherwise, what error are you getting

Ruby on Rails default value on form

Hey, need a little help here.
I have two models:
class User < ActiveRecord::Base
has_many :jobs
end
and
class Job < ActiveRecord::Base
belongs_to :user
end
When i do migration i put
class CreateJobs < ActiveRecord::Migration
def self.up
create_table :jobs do |t|
t.references :user
.....
What should i put on my jobs/new action for user_id?
I use resfull_authentication, so i have current_user helper.
<% form_for(#job) do |f| %>
<%= f.error_messages %>
<p>
User:
<%= f.label current_user.login %> #works fine for me! current_user.id works fine two!
??????????????? But what should i put for value???????
</p>
<p>
<%= f.label :filename %><br />
<%= f.text_field :filename %>
</p>
Should i put current_user.id on controller? If so, how ?
Please help! Thank you very much!
Edit after more info:
In your controller, do something like:
#user = User.find_by_id(session[:user_id])
#job = Job.new(params[:job])
#user.jobs << job
Original answer:
You could have something like:
<%= f.collection_select :user_id, User.find(:all, :order => "name ASC"),
:id, :name, {:include_blank => true} %>
This'll give you a dropdown with user names in alphabetical order.
def new
#job = current_user.jobs.new
end
def create
#job = current_user.jobs.build(params[:job])
if #job.save
redirect_to #job
else
render 'new'
end
end
When the job gets created, the user_id column will automatically be assigned to the current_user id.
Is this what you're trying to do?
You can use hidden field tag.
View:
<%= hidden_field_tag 'user_id', current_user.id %>

Resources