Ruby on rails Ruby mixin模块的规格有问题
我对mixin模块没有很好的经验。那么,如果我的问题有点天真,请原谅我 我正在创建几个模块,将一个项目与音乐服务(如Spotify)集成,后者拥有REST API。所有这些模块都包括我创建的另一个名为APIClientBuilder的mixin模块,它提供了一个用于创建API端点的小型DSL lib/integrations/api\u client\u builder.rbRuby on rails Ruby mixin模块的规格有问题,ruby-on-rails,ruby,rspec,module,Ruby On Rails,Ruby,Rspec,Module,我对mixin模块没有很好的经验。那么,如果我的问题有点天真,请原谅我 我正在创建几个模块,将一个项目与音乐服务(如Spotify)集成,后者拥有REST API。所有这些模块都包括我创建的另一个名为APIClientBuilder的mixin模块,它提供了一个用于创建API端点的小型DSL lib/integrations/api\u client\u builder.rb require 'rest-client' module APIClientBuilder attr_acces
require 'rest-client'
module APIClientBuilder
attr_accessor :api_client, :endpoint, :url, :param
def api_client(api_name)
end
def fetch_client(api_name)
end
def api_endpoint(endpoint_name)
end
def fetch_endpoint(api_name,endpoint_name)
end
def method=(meth)
end
def url=(endpoint_url)
end
def param(param_name,param_value)
end
def call(api_name,api_endpoint,token,*extra_params)
end
end
require_relative 'api_client_builder'
module SpotifyIntegration
include APIClientBuilder
def base_url
'https://api.spotify.com/v1'
end
def random_state_string
(0..10).map { (65 + rand(26)).chr }.join
end
api_client('spotify') do |apic|
apic.api_endpoint('request_authorization') do |ep|
ep.method = :get
ep.url = "https://accounts.spotify.com/authorize"
ep.param("client_id",SPOTIFY_KEY)
ep.param("response_type","code")
ep.param("redirect_uri","http://localhost:3000")
end
apic.api_endpoint('my_playlists') do |ep|
ep.method = :get
ep.url = "#{base_url}/me/playlists"
end
end
end
require 'integrations/spotify.rb'
class UsersController < ApplicationController
include SpotifyIntegration
end
require 'rails_helper'
require 'integrations/spotify'
class SpotifyClientTester
include SpotifyIntegration
end
RSpec.describe SpotifyIntegration do
context 'Auxiliary methods' do
it 'Two calls to random_state_string shall generate two different strings' do
obj = SpotifyClientTester.new
s1 = obj.random_state_string
s2 = obj.random_state_string
expect(s1).not_to eq(s2)
end
end
end
lib/integrations/spotify.rb
require 'rest-client'
module APIClientBuilder
attr_accessor :api_client, :endpoint, :url, :param
def api_client(api_name)
end
def fetch_client(api_name)
end
def api_endpoint(endpoint_name)
end
def fetch_endpoint(api_name,endpoint_name)
end
def method=(meth)
end
def url=(endpoint_url)
end
def param(param_name,param_value)
end
def call(api_name,api_endpoint,token,*extra_params)
end
end
require_relative 'api_client_builder'
module SpotifyIntegration
include APIClientBuilder
def base_url
'https://api.spotify.com/v1'
end
def random_state_string
(0..10).map { (65 + rand(26)).chr }.join
end
api_client('spotify') do |apic|
apic.api_endpoint('request_authorization') do |ep|
ep.method = :get
ep.url = "https://accounts.spotify.com/authorize"
ep.param("client_id",SPOTIFY_KEY)
ep.param("response_type","code")
ep.param("redirect_uri","http://localhost:3000")
end
apic.api_endpoint('my_playlists') do |ep|
ep.method = :get
ep.url = "#{base_url}/me/playlists"
end
end
end
require 'integrations/spotify.rb'
class UsersController < ApplicationController
include SpotifyIntegration
end
require 'rails_helper'
require 'integrations/spotify'
class SpotifyClientTester
include SpotifyIntegration
end
RSpec.describe SpotifyIntegration do
context 'Auxiliary methods' do
it 'Two calls to random_state_string shall generate two different strings' do
obj = SpotifyClientTester.new
s1 = obj.random_state_string
s2 = obj.random_state_string
expect(s1).not_to eq(s2)
end
end
end
我的想法是在我的控制器里有这样的东西:
app/controllers/api/v1/users\u controller.rb
require 'rest-client'
module APIClientBuilder
attr_accessor :api_client, :endpoint, :url, :param
def api_client(api_name)
end
def fetch_client(api_name)
end
def api_endpoint(endpoint_name)
end
def fetch_endpoint(api_name,endpoint_name)
end
def method=(meth)
end
def url=(endpoint_url)
end
def param(param_name,param_value)
end
def call(api_name,api_endpoint,token,*extra_params)
end
end
require_relative 'api_client_builder'
module SpotifyIntegration
include APIClientBuilder
def base_url
'https://api.spotify.com/v1'
end
def random_state_string
(0..10).map { (65 + rand(26)).chr }.join
end
api_client('spotify') do |apic|
apic.api_endpoint('request_authorization') do |ep|
ep.method = :get
ep.url = "https://accounts.spotify.com/authorize"
ep.param("client_id",SPOTIFY_KEY)
ep.param("response_type","code")
ep.param("redirect_uri","http://localhost:3000")
end
apic.api_endpoint('my_playlists') do |ep|
ep.method = :get
ep.url = "#{base_url}/me/playlists"
end
end
end
require 'integrations/spotify.rb'
class UsersController < ApplicationController
include SpotifyIntegration
end
require 'rails_helper'
require 'integrations/spotify'
class SpotifyClientTester
include SpotifyIntegration
end
RSpec.describe SpotifyIntegration do
context 'Auxiliary methods' do
it 'Two calls to random_state_string shall generate two different strings' do
obj = SpotifyClientTester.new
s1 = obj.random_state_string
s2 = obj.random_state_string
expect(s1).not_to eq(s2)
end
end
end
但当我运行它时,我得到了
未定义的本地变量或方法base\u url
用于SpotifyIntegration:Module(nameferror)
我不确定我错过了什么。也许我应该使用extend
而不是include
。我总是对此感到困惑
有人能帮我找到正确的路吗?我已经与这个错误斗争了整整一个下午。如果您想使用在模块
SpotifyIntegration
的类级别定义的方法,您需要扩展APIClientBuilder
module SpotifyIntegration
extend APIClientBuilder
另外,
base\u url
也必须是一个类方法,def self.base\u url
如果要使用在模块SpotifyIntegration
的类级别定义的方法,则需要扩展APIClientBuilder
module SpotifyIntegration
extend APIClientBuilder
另外,
base\u url
也必须是类方法,def self.base\u url
您误用了mixin。对于经典继承不适合向对象添加一组特征的情况,请使用mixin
例如:
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments, as: :commentable
end
# ...
end
class Video < ApplicationRecord
include Commentable
end
class Hotel < ApplicationRecord
include Commentable
end
为什么不将API客户机混合到控制器或模型中?因为单一责任原则和事实,使用较小的部分来做有限的事情比创建上帝类更可取 你误用了mixin。对于经典继承不适合向对象添加一组特征的情况,请使用mixin 例如:
module Commentable
extend ActiveSupport::Concern
included do
has_many :comments, as: :commentable
end
# ...
end
class Video < ApplicationRecord
include Commentable
end
class Hotel < ApplicationRecord
include Commentable
end
为什么不将API客户机混合到控制器或模型中?因为单一责任原则和事实,使用较小的部分来做有限的事情比创建上帝类更可取 它在哪一条线上失败了?您甚至没有在测试中调用
base\u url
方法,而且random\u state\u string
也没有调用base\u url
lib/integrations/spotify.rb:33
,这表示ep.url=“{base\u url}/me/playlists”
。你说的正是我最困惑的地方。我甚至不调用base\u url
。这不在这篇文章的片段中,ep.url=“{base\u url}/me/playlists”
。抱歉,我现在编辑了它。我错误地删除了这个部分。这是在班级层面上的原因吗?api|U客户端(“spotify”)do | apic |----------在哪一行发生故障?您甚至没有在测试中调用base\u url
方法,而且random\u state\u string
也没有调用base\u url
lib/integrations/spotify.rb:33
,这表示ep.url=“{base\u url}/me/playlists”
。你说的正是我最困惑的地方。我甚至不调用base\u url
。这不在这篇文章的片段中,ep.url=“{base\u url}/me/playlists”
。抱歉,我现在编辑了它。我错误地删除了这个部分。这是在班级层面上的原因吗?api_client(“spotify”)do | apic |------------------在SpotifyIntegration
中扩展它?在SpotifyIntegration
中扩展它?是的,如果您不打算创建它的实例,客户端可以是一个模块。但在大多数情况下,您希望将客户机和服务对象设置为类,以便更容易通过初始值设定项注入配置。是的,如果您不打算创建其实例,则客户机可以是一个模块。但在大多数情况下,您希望将客户机和服务对象设置为类,以便更容易通过初始值设定项注入配置。