从 URL 请求 Rails 模型的一部分
Request part of a Rails model from URL
我有一个名为 Tasks
的 Rails 模型,它只有一个属性:resource_id
。这是指另一个 Rails 网站 运行 上的 Resource
(另一个模型)的 ID,在不同的 URL 上使用不同的数据库。
当您请求 Resource
(例如 http://localhost:3020/resources/23.json
)时,它 returns 资源采用 JSON 格式,例如:
{
"title": "Hello",
"description": "Lorem ipsum..."
}
我希望能够从我当前的 Rails 网站(带有 Task
的网站)引用所请求的资源:
# returns a Task with `resource_id: 23`
@task = Task.find(1)
# refers to the Resource from the other Rails server
@task.resource.title
如何让 Rails 在从本地数据库中找到 Task
的同时获取 Resource
?
我尝试在 task.rb
中创建一个 resource
属性,它在这样调用时请求 Resource
:
require 'net/http'
class Task < ApplicationRecord
def resource
res = Net::HTTP.get(URI.parse('http://localhost:3020/resources/' + resource_id.to_s + '.json'))
JSON.parse(res)
end
end
但是,它运行 每次 我调用 task.resource
这非常慢。我可以只请求一次 Resource
并将其存储在本地某种伪属性中吗(我不知道它叫什么)?
您需要将关联添加到任务和资源:
在 task.rb 中:
has_many: :resources
在resource.rb中:
belongs_to: :task
这些关联会自动将方法(例如您的资源方法)添加到模型中:https://guides.rubyonrails.org/association_basics.html
然后在您的控制器操作中,使用 :includes 连接两个表:
@tasks = Task.includes(:resource)
看这里:https://apidock.com/rails/ActiveRecord/QueryMethods/includes
这里有一个解释:https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
以下是我如何解决自己的问题:
首先,向 Task
添加一个名为 resource_string
的字符串属性。
task.rb
require 'net/http'
class Task < ApplicationRecord
def resource
JSON.parse(resource_string)
end
after_find do |task|
task.resource_string = request_resource task
end
private
def request_resource(task)
Net::HTTP.get(URI.parse('http://localhost:3020/resources/' + task.resource_id.to_s + '.json'))
end
end
然后您可以按如下方式访问资源:
@task = Task.find(1)
@task.resource['title']
只会发起一次请求,调用find方法后写入resource_string
属性
查询外部数据库的所有内容table效率不高。但是你可以为你的控制器添加一个缓存:
例如,你可以使用redis缓存:
require 'net/http'
class Task < ApplicationRecord
def resource
res = $redis.fetch(:resource, expires_in: 1.hour) do
Net::HTTP.get(URI.parse('http://localhost:3020/resources/' + resource_id.to_s + '.json'))
JSON.parse(res)
end
end
end
我有一个名为 Tasks
的 Rails 模型,它只有一个属性:resource_id
。这是指另一个 Rails 网站 运行 上的 Resource
(另一个模型)的 ID,在不同的 URL 上使用不同的数据库。
当您请求 Resource
(例如 http://localhost:3020/resources/23.json
)时,它 returns 资源采用 JSON 格式,例如:
{
"title": "Hello",
"description": "Lorem ipsum..."
}
我希望能够从我当前的 Rails 网站(带有 Task
的网站)引用所请求的资源:
# returns a Task with `resource_id: 23`
@task = Task.find(1)
# refers to the Resource from the other Rails server
@task.resource.title
如何让 Rails 在从本地数据库中找到 Task
的同时获取 Resource
?
我尝试在 task.rb
中创建一个 resource
属性,它在这样调用时请求 Resource
:
require 'net/http'
class Task < ApplicationRecord
def resource
res = Net::HTTP.get(URI.parse('http://localhost:3020/resources/' + resource_id.to_s + '.json'))
JSON.parse(res)
end
end
但是,它运行 每次 我调用 task.resource
这非常慢。我可以只请求一次 Resource
并将其存储在本地某种伪属性中吗(我不知道它叫什么)?
您需要将关联添加到任务和资源:
在 task.rb 中:
has_many: :resources
在resource.rb中:
belongs_to: :task
这些关联会自动将方法(例如您的资源方法)添加到模型中:https://guides.rubyonrails.org/association_basics.html
然后在您的控制器操作中,使用 :includes 连接两个表:
@tasks = Task.includes(:resource)
看这里:https://apidock.com/rails/ActiveRecord/QueryMethods/includes
这里有一个解释:https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
以下是我如何解决自己的问题:
首先,向 Task
添加一个名为 resource_string
的字符串属性。
task.rb
require 'net/http'
class Task < ApplicationRecord
def resource
JSON.parse(resource_string)
end
after_find do |task|
task.resource_string = request_resource task
end
private
def request_resource(task)
Net::HTTP.get(URI.parse('http://localhost:3020/resources/' + task.resource_id.to_s + '.json'))
end
end
然后您可以按如下方式访问资源:
@task = Task.find(1)
@task.resource['title']
只会发起一次请求,调用find方法后写入resource_string
属性
查询外部数据库的所有内容table效率不高。但是你可以为你的控制器添加一个缓存:
例如,你可以使用redis缓存:
require 'net/http'
class Task < ApplicationRecord
def resource
res = $redis.fetch(:resource, expires_in: 1.hour) do
Net::HTTP.get(URI.parse('http://localhost:3020/resources/' + resource_id.to_s + '.json'))
JSON.parse(res)
end
end
end