代码之家  ›  专栏  ›  技术社区  ›  Ulysse BN

如何从两个不同的外键访问模型?

  •  1
  • Ulysse BN  · 技术社区  · 6 年前

    我有两个相关的模型,旅行和乘坐。一次旅行可能有一次旅行或一次回程旅行。我的ActiveRecord模型如下:

    class Route < ActiveRecord::Base
        has_one :trip
    end
    
    class Trip < ActiveRecord::Base
        belongs_to :going_route,     class_name: "Route"
        belongs_to :returning_route, class_name: "Route"
    end
    

    但是,当我想从一条路线上访问一次旅行时,这会给我带来一个问题:

    Route.first.trip
    

    这将引发PostgreSQL错误:

    pg::undefinedcolumn:错误:列trips.route id不存在

    我怎样才能告诉 Route 他旅行的班级 going_route_id returning_route_id ?或者也许还有别的办法?

    P.S:我一直在寻找类似的问题,有很多,但没有一个完全像这个问题,解决了我的问题。如果你对如何使区别更清楚有什么建议,尤其是标题。 Here 是类似的问题吗


    编辑:

    我也试过使用lambda,比如 matthew's duplicate proposition :

    class FavoriteRoute < ActiveRecord::Base
        has_one :favorite_trip, -> (route) { where("going_route_id = :id OR returning_route_id = :id", id: route.id) }
    end
    

    这将引发相同的错误。如果我认为我应该使用 find_by 而不是 where 因为我只需要一个结果,我还有一个错误,我真的不明白:

    nomethodError:未定义的方法'except',用于行程:0x0007F827B9D13E0>

    4 回复  |  直到 5 年前
        1
  •  2
  •   max Mike Williams    6 年前

    belongs_to has_one has_many

    class Trip < ActiveRecord::Base
        # specifying foreign_key here is not needed since AR
        # will deduce that its outbound_route_id
        belongs_to :outbound_route,
          class_name: "Route"
        belongs_to :return_route, 
          class_name: "Route"
    end
    
    class Route < ActiveRecord::Base
      has_one :trip_as_outbound,
        class_name: 'Trip',
        foreign_key: :outbound_route_id
      has_one :trip_as_returning,
        class_name: 'Trip',
        foreign_key: :return_route_id
    
      def trip
        trip_as_outbound || trip_as_returning
      end
    end
    

    class Route < ApplicationRecord 
    end
    
    class Routes::Outbound < ::Route
      self.table_name = 'routes'
      has_one :trip, foreign_key: :outbound_route_id
    end
    
    class Routes::Return < ::Route
      self.table_name = 'routes'
      has_one :trip, foreign_key: :return_route_id
    end
    
    class Trip < ApplicationRecord
      belongs_to :outbound_route,
        class_name: '::Routes::Outbound'
      belongs_to :return_route,
        class_name: '::Routes::Return'
    end
    

    Routes::Return.all Route.all

    type routes

        2
  •  1
  •   Jocko    6 年前

    going returning

    trip_routes

    create_table :trip_routes do |t|
       t.integer :trip_id
       t.integer :route_id
       t.string  :route_type
       t.boolean :favorite
    end
    
    # Consider this part based on how you think your indexes are best built, I'm 
    # just making note that DB performance can be impacted particularly on these
    # two fields.
    add_index :trip_routes, :trip_id
    add_index :trip_routes, :route_id
    

    trip_route

    class TripRoute < ActiveRecord::Base
        belongs_to :trip
        belongs_to :route
    
        # This model knows whether it's the 'going' or 'returning' route, so do your 
        # route functionality here.
    end
    

    trip

    class Trip < ActiveRecord::Base
        has_many :trip_routes
        has_many :route, through: trip_routes
    
        # Helper to get the going route
        def going_trip_route
            self.trip_routes.find_by(route_type: "going")
        end
    
        # Helper to get the going route
        def returning_trip_route
            self.trip_routes.find_by(route_type: "returning")
        end
    
    end
    

    route

    class Route < ActiveRecord::Base
        has_many :trip_routes
        has_many :trips, through: trip_routes
    end
    
        3
  •  0
  •   Ulysse BN    6 年前

    class Route
        def trip
            @trip ||= Trip.find_by("going_route_id = :id OR returning_route_id = :id", id: id)
        end
    end
    

        4
  •  0
  •   Christian Angel Galamay    6 年前

    add_column :routes, :going_key,     :integer
    add_column :routes, :returning_key, :integer
    

    class Route < ActiveRecord::Base
      belongs_to :going_route, foreign_key: :going_key, class_name: Trip
      belongs_to :returning_route, foreign_key: :returning_key, class_name: Trip
    end
    
    class Trip < ActiveRecord::Base
    end
    
    Route.first.going_route 
    Route.first.returning_route