Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing join model attributes in has_many: though relationship

I have this models and association many-to-many : through:

class RailwayStation < ActiveRecord::Base
  has_many :railway_stations_routes
  has_many :routes, through: :railway_stations_routes
end

class Route < ActiveRecord::Base
  has_many :railway_stations_routes
  has_many :railway_stations, through: :railway_stations_routes
end

class RailwayStationsRoute < ActiveRecord::Base
  belongs_to :railway_station
  belongs_to :route
end

I added the column st_index:

add_column :railway_stations_routes, :st_index, :integer

for index station in route, but I don't understand how change it from route view form:

ul
  - @route.railway_stations.each do |railway_station|
   li = railway_station.title
      = ????
like image 902
Vadim Sergeevich Avatar asked Oct 31 '22 17:10

Vadim Sergeevich


1 Answers

First you need to correct the naming scheme for your models and tables so that they follow the rails conventions.

Run this from the command line:

$ rails g migration RenameRailwayStationsRoute

And edit the migration in 'db/migrations' to read:

class RenameRailwayStationsRoute < ActiveRecord:Migration
  def change
    rename_table :railway_stations_route, :railway_station_routes
  end 
end 

Run the migration

$ rake db:migrate

Rename the model file:

$ cd app/models
$ mv railway_stations_route.rb railway_station_route.rb

Or if you are using GIT

$ git mv railway_stations_route.rb railway_station_route.rb

Edit your models to use the correct naming:

class RailwayStation < ActiveRecord::Base
  has_many :railway_station_routes
  has_many :routes, through: :railway_station_routes
end

class RailwayStationRoute < ActiveRecord::Base
  belongs_to :railway_station
  belongs_to :route
end

class Route < ActiveRecord::Base
  has_many :railway_station_routes
  has_many :railway_stations, through: :railway_station_routes
end

Add associated records to a form

The simplest way is to use the simple_form gem. After following the instructions instructions (and remember to restart your rails server) add the form:

<%= simple_form_for(@route) do |f| %>
  <%= f.association :stations, collection: Station.all, name_method: :title %>
<% end %>

Without simple form you could do it something like this:

<%= form_for(@route) do |f| %>
  <%= f.collection_check_boxes(:stations_ids, Station.all, :id, :title) do |b| 
    b.label { b.checkbox checked: @route.stations_ids.include?(object.id) } 
  end %>
<% end %>
  • https://github.com/plataformatec/simple_form#associations
  • http://apidock.com/rails/v4.0.2/ActionView/Helpers/FormOptionsHelper/collection_check_boxes

Added - accessing the join model

There is no unfortunatly no straight forward way to to access the properties of the join model from one end of a many to many relationship.

This is due to the fact that Rails does not keep track of where the model was loaded from well at least not in the way you want. (it does - but it's pretty complicated).

One way to solve this would be to do:

class RoutesController < ApplicationController
  def show
    @route = Route.eager_load(railway_station_routes: :railway_station).find(params[:id])
  end
end

We join in both models with eager_load so that rails runs one database query and loads both the railway_station_routes and railway_station.

You would then loop through the join model instead of the stations:

ul
  - @route.railway_station_routes.each do |rs|
    li
      # note that you cannot both use = and have a body in HAML/Slim
      p = "index: #{ rs.st_index }"
      p = rs.railway_station.title
like image 159
max Avatar answered Nov 08 '22 06:11

max