中继重新获取失败...错误中继无法协调连接上的边缘

Posted

技术标签:

【中文标题】中继重新获取失败...错误中继无法协调连接上的边缘【英文标题】:Relay re-fetching failed... error Relay was unable to reconcile edges on a connection 【发布时间】:2016-11-24 12:08:51 【问题描述】:

请帮忙!也许有人已经遇到了我的问题....

当使用更新的变量重新获取数据时 -- 使用 relay.setVariables() -- 我收到错误 "Relay 无法协调连接上的边缘。这很可能在尝试处理服务器响应时发生,该响应包括与缺少id 字段的节点的连接边缘。” 尽管数据正确,但中继存储并未更新。

见下面的代码...(Ruby && ES6)

宝石文件

gem 'graphql', '0.16.0'
gem 'graphql-relay', '0.11.2'

....服务器端代码

node_identification.rb

NodeIdentification = GraphQL::Relay::GlobalNodeIdentification.define do
object_from_id -> (id, ctx) do
    type, id = NodeIdentification.from_global_id(id)
    case type
        when 'FrontApp'
            Relay::FrontApp::STATIC
        else
            Object.const_get(type).find_by(id: id)
    end
end

type_from_object -> (obj) do
    begin
        MODEL_TO_TYPE[obj.class.name.to_sym].constantize
    rescue
        (obj.class.name + 'Type').constantize
    end
end
end

MODEL_TO_TYPE = 
   :'Relay::FrontApp' => 'FrontAppType'

front_app_query_type.rb

FrontAppQueryType = GraphQL::ObjectType.define do
name 'FrontAppRootQuery'
field :node, field: NodeIdentification.field

field :main, FrontAppType do
    resolve -> (obj, args, ctx) 
        Relay::FrontApp::STATIC
    
end
end

front_app_type.rb

FrontAppType = GraphQL::ObjectType.define do
name 'FrontApp'
# field :node, field: NodeIdentification.field
interfaces [NodeIdentification.interface]
global_id_field :id

field :tips, TipsType do
    argument :filters, types.String
    resolve -> (obj, args, ctx) 
        filters = args[:filters]
        begin
            filters = JSON.parse(filters).deep_symbolize_keys!
        rescue
            filters = nil
        end
        ctx[:filters] = filters
        Relay::Tips::STATIC
    
end
connection :footer, FooterMenuItemType.connection_type do
    argument :id, types.ID!
    resolve ->(obj, args, ctx)
        ::Footer.order(:id)
    
end
end

tips_connection_type.rb

TipsConnectionType = TipShowType.define_connection do
field :totalCount, types.Int do
    resolve -> (obj, args, ctx) 
        obj.object.size
    
end
end


TipsType = GraphQL::ObjectType.define do
name 'Tips'
description 'Tips list for home page'
interfaces [NodeIdentification.interface]
global_id_field :id

connection :mostRecent, TipsConnectionType do
    argument :limit, types.Int
    resolve ->(obj, args, ctx)
        tips = ::Tip.active_users.started(Time.zone.now.in_time_zone(ctx[:current_user] ? ctx[:current_user].time_zone : ::User.get_locally_time_zone).to_date).ready.active.moderated.published.includes(:comments, :tip_type).order('created_at desc').limit(args[:limit])
        TipHelpers::Filter.filter(tips: tips, filters: ctx[:filters], reorder: 'created_at desc')
    
end
connection :mostPopular, TipsConnectionType do
    argument :limit, types.Int
    resolve ->(obj, args, ctx)
        tips = ::Tip.active_users.started(Time.zone.now.in_time_zone(ctx[:current_user] ? ctx[:current_user].time_zone : ::User.get_locally_time_zone).to_date).ready.active.moderated.published.includes(:comments, :tip_type).order('(SELECT COUNT(*) FROM comments WHERE tid = tips.id) desc').limit(args[:limit])
        TipHelpers::Filter.filter(tips: tips, filters: ctx[:filters], reorder: '(SELECT COUNT(*) FROM comments WHERE tid = tips.id) desc')
    
end
end

/app/models/relay/front_app.rb

module Relay
class FrontApp < Struct.new :id
    # HACK::// For relay root queries
    STATIC = new(id: 'main').freeze

    def initialize *args
        opts = args.last.is_a?(Hash) ? args.pop : Hash.new
        super *args
        opts.each_pair do |k, v|
            self.send "#k=", v
        end
    end

    def self.find(_)
        STATIC
    end
end
end

** /app/models/relay/tips.rb**

module Relay
class Tips < Struct.new :id
    # HACK:// For relay root queries
    STATIC = new(id: 'tips').freeze

    def initialize *args
        opts = args.last.is_a?(Hash) ? args.pop : Hash.new
        super *args
        opts.each_pair do |k, v|
            self.send "#k=", v
        end
    end

    def self.find(_)
        STATIC
    end

end
end

....和客户端代码

class MainApp extends React.Component 

constructor(props) 
    super(props);

    this.state = 
        filters: filtersTemplate
    ;

    this.setFilter = this.setFilter.bind(this);


setFilter(filter, value, e) 
    if (e) 
        e.nativeEvent.stopImmediatePropagation();
        e.preventDefault();
    

    let  filters  = this.state;
    if (['currency', 'sum'].inArray(filter)) 
        filters.funds[filter] = value;
     else 
        filters[filter] = value;
    
    this.setState(
        filters: filters
    );
    this.props.relay.setVariables(filters: filters);


render() 
    let  tips  = this.props.main;
    let renderTipsSection = (section) => 
        let tipsCount = tips[section] ? tips[section].edges.length : 0;
        let blankCount = 10 - tipsCount;
        return (
            <ul className="tips__list">
                
                    tips[section] && tips[section].edges.map((node) => (
                        <li key=node.id className="tips__list_item">
                            <TipCard node=node/>
                        </li>
                    ))
                
                
                    [...new Array(blankCount).keys()].map((item, idx) => (
                        <li key=idx className="tips__list_item">
                            <TipCard dummy=true/>
                        </li>
                    ))
                
            </ul>
        );
    ;
    return (
        <div>
            <div className="wrapper">
                <div className="TipsWrapper">
                    <div className="wrapper">

                         renderTipsSection('mostRecent') 

                         renderTipsSection('mostPopular') 

                    </div>
                </div>
            </div>
        </div>
    );


export default Relay.createContainer(MainApp, 
initialVariables: 
    filters: 
        category: null,
        funds: 
            currency: null,
            sum: null
        ,
        date: null,
        location: null,
        browse: null
    
,
prepareVariables: (prevVars) => 
    return 
        ...prevVars,
        filters: JSON.stringify(prevVars.filters)
    
,
fragments: 
    main: () => Relay.QL`
        fragment on FrontApp 
            tips(filters: $filters) 
              mostRecent(first: 10, limit: 10)
                edges 
                  node 
                    id
                    tid
                    title_name
                    category
                  
                
                
              mostPopular(first: 10, limit: 10)
                edges 
                  node 
                    id
                    tid
                    title_name
                    category
                  
                
                
            
        
    `
);

当 setFilter() 触发时,将调用 relay.setVariables... 结果……

[RELAY-NETWORK] Run query q3 Object relayReqId: "q3", relayReqObj: RelayQueryRequest, relayReqType: "query", method: "POST", headers: Object…
[RELAY-NETWORK] query q3: 3429ms
Warning: Relay was unable to reconcile edges on a connection. This most likely occurred while trying to handle a server response that includes connection edges with nodes that lack an `id` field

【问题讨论】:

能否也包含TipShowType 的代码? (那是有问题的连接的edge,对吧?) 发送到https://github.com/rmosolgo/graphql-relay-ruby/issues/61 我通过 FIELDS_CHANGE 行为解决了这个问题 上面可以看到的解决方案 你应该把你的问题和答案分开。 【参考方案1】:

经过数小时的折腾,找到了上述问题的解决方案……见下文

解决方案

客户端突变

export default class ApplyFiltersMutation extends Relay.Mutation 
static fragments = 
    tips: () => Relay.QL`
        fragment on Tips  
            id 
        
    `,
;

getMutation() 
    return Relay.QL`mutation 
        applyFilters
    `;


getVariables() 
    return 
        filters: this.props.filters
    ;


getFatQuery() 
    return Relay.QL`
        fragment on ApplyFiltersPayload 
            tips
        
    `;


getConfigs() 
    return [
        
            type: 'FIELDS_CHANGE',
            fieldIDs: tips: this.props.tips.id,
        
    ];


服务器端

home_mutations.rb

module HomeMutations
  ApplyFilters = GraphQL::Relay::Mutation.define do
    name 'ApplyFilters'
    input_field :filters, !types.String

    return_field :tips, BipsType

    resolve -> (args, ctx) 
        filters = args[:filters]
        begin
            filters = JSON.parse(filters).deep_symbolize_keys!
        rescue
            filters = nil
        end
        ctx[:filters] = filters

        
            tips: Relay::Tips::STATIC
        
    
  end
end

tips_type.rb

include TipHelpers::Filter

TipsType = GraphQL::ObjectType.define do
name 'Tips'
description 'Tips list for home page'
interfaces [NodeIdentification.interface]
global_id_field :id

connection :almostRaised, TipsConnectionType do
    resolve ->(obj, args, ctx)
        TipHelpers::Filter.filter(section: 'almost_raised', filters: ctx[:filters], current_user: ctx[:current_user])
    
end

...

end
end

lib/tip_helpers.rb

class TipHelpers
module Filter

    def filter(section:, filters:, current_user:)

        ...

        # p tips.reorder(reorder).to_sql
        tips.reorder(reorder)
    end
end
end

【讨论】:

答案能否具体说明解决方案的具体应用位置?

以上是关于中继重新获取失败...错误中继无法协调连接上的边缘的主要内容,如果未能解决你的问题,请参考以下文章

尝试从反应应用程序连接到 graphcool 中继 API 时出现此错误:模块构建失败:错误:没有有效的 GraphQL 端点

扫描仪通过SMTP中继服务器发送通知邮件失败

使用 O365 帐户连接到 Azure VM 中的 SMTP 中继失败

磊科路由器NW625PLUS无线WIFI中继教程

华硕路由器ac68u怎么做无线中继

将边缘插入中继连接的正确方法是啥?