2016-11-29 43 views
0

那么,像往常一样,我已经把自己与轨道“逻辑”绑在一起,并且令人沮丧,无法相信。Rails的“逻辑”似乎暗指我

如果我能在常规的SQL把这事办成它想:

SELECT points.genus, types.type_name 
FROM types, points 
WHERE types.id = points.type_id and genus='Malus'; 

我似乎无法模仿此查询中轨的输出。我似乎能够期待的最好结果是:

Point 
    .select(:genus, :type_id) 
    .where("genus = 'Malus'") 
    .joins(:type) 

太好了,我可以在我的`point.rb添加belongs_to :type进入依靠轨协会输出在我看来,正确的价值”,万物出来hunky-dory。

但是,我需要将types.type_name传递给模型中的某些代码。如果我使用:type_id(除了获得一个值而不是我需要的字符串),一切都按预期工作。我试过'types.type_name':type_name这两者都会产生一个NIL。 :type.type_name生成以下错误:

undefined method `type_name' for :types:Symbol

作为一个方面说明,我没有创造我想要的字符串传递到模型的代码。它从我传递它的变量中构建JSON,并且不关心它是一个字符串还是一个数字,也不关心我传递它的变量。

--update添加实际的代码,而不仅仅是理论,每@丹的要求 -

create_points.rb

class CreatePoints < ActiveRecord::Migration 
    def change 
    create_table :points do |t| 
     t.string :genus 
     t.string :species 
     t.string :cultivar 
     t.string :common_name 
     t.references :type, index: true, foreign_key: true 

     t.timestamps null: false, default: Time.now 
     t.multi_point :geom, srid: 4326 
    end 
end 

create_types.rb

class CreateTypes < ActiveRecord::Migration 
    def change 
    create_table :types do |t| 
     t.string :type_name 

     t.timestamps null: false 
    end 

plants_controller.rb

class PlantsController < ApplicationController 
    def map 
    @points = Point 
     .select('points.genus, points.species, points.cultivar, points.common_name, types.type_name') 
     .where("types.type_name like 'Tree-%' or types.type_name like 'Shrub-%' or types.type_name like 'Perennial' or types.type_name like 'Fern' or types.type_name like 'Vine-%'") 
     .order(:id) 
     .eager_load(:type) 
    feature_collection = Point.to_feature_collection @points 
    @geojson = RGeo::GeoJSON.encode(feature_collection) 

    respond_to do |format| 
     format.json { render json: @geojson } 
     format.html 
    end 

type.rb

class Type < ActiveRecord::Base 
    has_many :points 
end 

point.rb

class Point < ActiveRecord::Base 
    belongs_to :type 
    include Featurable 

    featurable :geom, [:genus, :species, :cultivar, :common_name, :type_id] 
end 

concerns/featurable.rb

module Featurable 
    extend ActiveSupport::Concern 

    module ClassMethods 
    def featurable geom_attr_name, property_names = [] 
     define_method :to_feature do 
     factory = RGeo::GeoJSON::EntityFactory.instance 

     property_names = Array(property_names) 
     properties = property_names.inject({}) do |hash, property_name| 
      hash[property_name.to_sym] = read_attribute(property_name) 
      hash 
     end 
     factory.feature read_attribute(geom_attr_name), self.id, properties 
     end 
    end 

    # turns a collection of models to a feature collection 
    # All models in the collection should implement the to_feature method 
    def to_feature_collection models 
     factory = RGeo::GeoJSON::EntityFactory.instance 
     features = models.map(&:to_feature) 
     factory.feature_collection features 
    end 
    end 
end 

featurable :geom, [:genus ...行我想使用type.type_name的值,而不是point.type_id。

--update 2重新发布point.rb -

class Point < ActiveRecord::Base 
    belongs_to :type 
    include Featurable 

    def to_feature 
    factory = RGeo::GeoJSON::EntityFactory.instance 

    property_names = [:genus, :species, :cultivar, :common_name, :type_name] 

    properties = property_names.inject({}) do |hash, property_name| 
     hash[property_name] = self.send(property_name) 
     hash 
    end 
    factory.feature geom, self.id, properties 
    end 

    delegate :type_name, to: :type 
    featurable :geom, [:genus, :species, :cultivar, :common_name, :type] 
end 
+0

如果您可以在两个有问题的模型中包含代码片段,以显示您的关系以及这两个表格的结构,可能会帮助您生成更多的答案。 – Dan

+0

@dan我已经添加了我的所有代码 – Ben

回答

1

我会说,你不应该试图找回从不同的表中的所有需要​​的列在同一个声明中,虽然作为一个SQL导向的人,我明白了这种本能。

我认为,关键就在这是要改变是:

featurable :geom, [:genus, :species, :cultivar, :common_name, :type_name] 

...然后获得分数的实例来响应与一个适当的值#type_name。你可以这样做:

delegate :type_name, to: :type 

你应该只需要急切的加载或加入:键入@points的定义,以使其高效。

编辑:由于使用了read_attribute,您可能必须在Point中定义自己的to_feature方法。

def to_feature 
    factory = RGeo::GeoJSON::EntityFactory.instance 

    property_names = [:genus, :species, :cultivar, :common_name, :type_name] 

    properties = property_names.inject({}) do |hash, property_name| 
    hash[property_name] = self.send(property_name) 
    hash 
    end 
    factory.feature geom, self.id, properties 
end 
+0

非常感谢你试图帮助我。 :)我不确定我了解你的建议。只需将委托行添加到我的模型中,不会更改JSON输出。组合代理命令并从特征行中删除'_name'会导致错误。 – Ben

+0

添加委托并使用:type_name应该已经做到了,但实际上@point的定义中的选择也应该被删除,我想。 –

+0

你想链接到一个数据库的副本bitbucket回购? – Ben

-1

您可以试试:

Point 
    .select('points.genus, types.type_name') 
    .where("genus = ?", "Malus") 
    .joins(:type) 
+0

对不起,如果我的帖子有点混乱 - 选择命令不是问题,它正在访问导致我适合的方法。这里是原始代码'featurable:geom,[:genus,:type_id]'但是我真的需要来自types.type_name的值。在附注中,当我将您的建议输入到rails控制台时,它完全忽略了type.type_name字段是它返回的数据。 – Ben