I've been working on this issue during the whole week, and despite many blogs that deal with this issue, like this, I'm having an error:
undefined method `employeurs'...
Let's imagine that you have two specific kinds of users, the employeurs and prestataires. First you fill in the user form with general information (name, email, etc). Then, you choose between the prestataire or employeur form, which will save the user form and redirect you to the second part of the inscription. Both employers and prestataires models have a belong_to relation with users.
With the code below, I've been able to create and save the user form, be redirected to the employer or prestataire form, create an employeur. Yet, when I use @user.employeurs
in the employeur controller, like in my index method, I get an error:
undefined method `employeurs'
despite my nested routes:
resources :users do
resources :employeurs
resources :prestataires
end
User model:
class User < ActiveRecord::Base
has_one :prestataire
has_one :employeur
has_secure_password
end
Employeur model:
class Employeur < ActiveRecord::Base
belongs_to :user
has_many :projets, as: :projetable
has_many :prestataires, through: :projets
has_many :offres, through: :projets
has_many :feedbacks, through: :projets
validates :siren, :societe, :code_postal, presence: true
end
User controller:
class UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
# GET /users/1/edit
def edit
@user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
@user = User.new(user_params)
respond_to do |format|
if @user.save
if params[:commit] == 'Prestataire'
format.html { redirect_to new_user_prestataire_path(user_id: @user), notice: "Renseignez vos informations d'employeur" }
format.json { render action: 'show', status: :created, location: @user }
else
format.html { redirect_to new_user_employeur_path(user_id: @user), notice: "Renseignez vos informations de prestataire" }
format.json { render action: 'show', status: :created, location: @user }
end
else
format.html { render action: 'new' }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1
# PATCH/PUT /users/1.json
def update
@user = User.find(params[:id])
respond_to do |format|
if @user.update(user_params)
if params[:commit] == 'Prestataire'
format.html { redirect_to new_user_prestataire_path(user_id: @user), notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { redirect_to new_user_employeur_path(user_id: @user), notice: "User was successfully updated." }
format.json { head :no_content }
end
else
format.html { render action: 'edit' }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
@user = User.find(params[:id])
@user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :surname, :forename, :civility, :phone)
end
end
Employeur controller:
class EmployeursController < ApplicationController
before_filter :load_user
def index
@employeurs = @user.employeurs.all
end
def show
@employeur = Employeur.find(params[:id])
end
def new
@employeur = @user.build_employeur
end
def edit
@employeur = Employeur.find(params[:id])
end
def create
@employeur = @user.build_employeur(employeur_params)
respond_to do |format|
if @employeur.save
format.html { redirect_to [@user, @employeur], notice: 'Employeur was successfully created.' }
format.json { render action: 'show', status: :created, location: @employeur }
else
format.html { render action: 'new' }
format.json { render json: @employeur.errors, status: :unprocessable_entity }
end
end
end
def update
@employeur = Employeur.find(params[:id])
respond_to do |format|
if @employeur.update_attributes(employeur_params)
format.html { redirect_to [@user, @employeur], notice: 'Employeur was successfully created.' }
format.json { render action: 'show', status: :created, location: @employeur }
else
format.html { render action: 'new' }
format.json { render json: @employeur.errors, status: :unprocessable_entity }
end
end
end
def destroy
@employeur = Employeur.find(params[:id])
@employeur.destroy
respond_to do |format|
format.html { redirect_to @user }
format.json { head :no_content }
end
end
private
def load_user
@user = User.find(params[:user_id])
end
def employeur_params
params.require(:employeur).permit(:siren, :societe, :code_postal)
end
end
User form:
<%= form_for(@user) do |f| %>
<% if @user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% @user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :civility, 'Titre de civilité: ' %><br>
<%= f.text_field :civility %>
</div>
<div class="field">
<%= f.label :forename, 'Prénom: ' %><br>
<%= f.text_field :forename %>
</div>
<div class="field">
<%= f.label :surname, 'Nom de famille: ' %><br>
<%= f.text_field :surname %>
</div>
<div class="field">
<%= f.label :email, 'Email: ' %><br>
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password, 'Mot de passe: ' %><br>
<%= f.password_field :password, size: 40 %>
</div>
<div class="field">
<%= f.label :password_confirmation, 'Confirmation de mot de passe: ' %><br>
<%= f.password_field :password_confirmation, size: 40 %>
</div>
<div class="field">
<%= f.label :phone, 'Numéro de téléphone: ' %><br>
<%= f.text_field :phone %>
</div>
<div class="actions">
<%= f.submit "Employeur" %>
<%= f.submit "Prestataire" %>
</div>
<% end %>
Employeur form:
<%= form_for [@user, @employeur] do |f| %>
<% if @employeur.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@employeur.errors.count, "error") %> prohibited this employeur from being saved:</h2>
<ul>
<% @employeur.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :siren, 'Siren: ' %><br>
<%= f.text_field :siren %>
</div>
<div class="field">
<%= f.label :societe, 'Société: ' %><br>
<%= f.text_field :societe %>
</div>
<div class="field">
<%= f.label :code_postal, 'Code Postal: ' %><br>
<%= f.text_field :code_postal %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Employeur index view:
<h1>Liste des employeurs</h1>
<ul>
<% @employeurs.each do |employeur| %>
<li><%= @user.employeur.siren %> | <%= @user.employeur.societe %> <%= @user.employeur.code_postal %> <%= link_to "++", user_employeur_path(employeur) %></li>
<% end %>
</ul>
Since I don't understand where this mistake can come from, I might have forgotten to add some useful parts of my code. Don't hesitate asking. Thank you in advance.
You’re confusing routes and models. Nesting routes doesn’t have any effect on the organisation of your models.
resources :users do
resources :employeurs
resources :prestataires
end
These routes have the effect of wiring particular URL requests to controller methods. They also set up helper methods like users_path
and such.
You declare your model like this:
class User < ActiveRecord::Base
has_one :employeur
end
So a User
has one Employeur
, why do you expect it to have more than one?
I’d recommend that you reconsider your entire model structure. It sounds to me that Employeur
and Prestataire
are actually just subtypes of User
, not their own types.