I am trying to make an app in Rails 4.
I have an industries model and a profiles model.
My industries table has:
create_table "industries", force: :cascade do |t|
t.string "sector"
t.string "icon"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "industries_organisations", id: false, force: :cascade do |t|
t.integer "industry_id"
t.integer "organisation_id"
end
add_index "industries_organisations", ["industry_id"], name: "index_industries_organisations_on_industry_id", using: :btree
add_index "industries_organisations", ["organisation_id"], name: "index_industries_organisations_on_organisation_id", using: :btree
create_table "industries_profiles", id: false, force: :cascade do |t|
t.integer "industry_id"
t.integer "profile_id"
end
add_index "industries_profiles", ["industry_id"], name: "index_industries_profiles_on_industry_id", using: :btree
add_index "industries_profiles", ["profile_id"], name: "index_industries_profiles_on_profile_id", using: :tree
The associations are:
profile.rb
has_and_belongs_to_many :industries
industry.rb
has_and_belongs_to_many :profiles
In my profiles show, I am trying to show the industry (sector attribute) associated with that profile.
I'm not sure how to do this using the HABTM join table association.
My current attempt is:
<% unless @profile.industries.blank? %>
<!-- @profile.industry.first.try(:sector) -->
<%= @Industry.sector.first = Industry.includes(:profile).where(profile: { @profile }) %>
<% end %>
The commented out line is my previous attempt.
I found this resource which I think I have followed Rails - HABTM Relationship -- How Can I Find A Record Based On An Attribute Of The Associated Model
How can I show a profile's industry sector?
Profiles controller has:
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
after_action :verify_authorized
# GET /profiles
# GET /profiles.json
def index
@profiles = Profile.all
authorize @profiles
end
# GET /profiles/1
# GET /profiles/1.json
def show
end
# GET /profiles/new
def new
@profile = Profile.new
@profile.qualifications_build
@profile.build_vision
@profile.build_personality
@profile.addresses_build
@profile.industries_build
authorize @profile
end
# GET /profiles/1/edit
def edit
@profile.build_personality unless @profile.personality
@profile.qualifications_build unless @profile.qualifications
@profile.build_vision unless @profile.vision
@profile.addresses_build unless @profile.addresses
@profile.industries.build unless @profile.industries
end
# POST /profiles
# POST /profiles.json
def create
@profile = Profile.new(profile_params)
authorize @profile
respond_to do |format|
if @profile.save
format.html { redirect_to @profile }
format.json { render :show, status: :created, location: @profile }
else
format.html { render :new }
format.json { render json: @profile.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /profiles/1
# PATCH/PUT /profiles/1.json
def update
# successful = @profile.update(profile_params)
# Rails.logger.info "xxxxxxxxxxxxx"
# Rails.logger.info successful.inspect
# user=@profile.user
# user.update.avatar
respond_to do |format|
if @profile.update(profile_params)
format.html { redirect_to @profile }
format.json { render :show, status: :ok, location: @profile }
else
format.html { render :edit }
format.json { render json: @profile.errors, status: :unprocessable_entity }
end
end
end
# DELETE /profiles/1
# DELETE /profiles/1.json
def destroy
@profile.destroy
respond_to do |format|
format.html { redirect_to profiles_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_profile
@profile = Profile.find(params[:id])
authorize @profile
end
# Never trust parameters from the scary internet, only allow the white list through.
def profile_params
params.require(:profile).permit(:user_id, :title, :hero, :overview, :research_interest, :occupation, :external_profile,
:working_languages, :tag_list,
user_attributes: [:avatar],
personality_attributes: [:average_day, :fantasy_project, :preferred_style],
vision_attributes: [:id, :profile_id, :long_term, :immediate_challenge],
qualifications_attributes: [:id, :level, :title, :year_earned, :pending, :institution, :_destroy],
addresses_attributes: [:id, :unit, :building, :street_number, :street, :city, :region, :zip, :country, :latitude, :longitude, :_destroy],
industries_attributes: [:id, :sector, :icon] )
end
end
The profiles form includes a form partial for the industry attributes as:
profiles form
<%= render 'industries/industry_selector', f: f %>
industries form
<%= simple_fields_for :industries do |iff| %>
<div class="form-inputs">
<%= iff.label "Choose your industry" %>
<%= iff.select :sector, options_from_collection_for_select(Industry.alphabetically, 'id', 'sector', @profile.industries.map{ |j| j.id }), :multiple => true %>
TAKING OLEG'S SUGGESTION BELOW
I try changing my show action in the profile controller to:
def show
@profile = Profile.includes(:industries).find(params[:id])
end
I get the same result - nothing shows for industry.
THE SOLUTION
The problem was that I named the join table industries profiles. I think its meant to be industry singular. This problem was resolved by naming the join table in the models so that it matches the definition I gave it in the schema.