Rails: 创建动态路由、控制器

Rails: Create Dynamic routes, controllers

我几乎没有公开为 REST API 端点的数据库视图。当前的实现是添加视图后,我们添加 Rails 代码,如

  1. 添加新路线
  2. 添加控制器和其他代码以查询returns json响应的视图

这种方法的缺点是我们每次添加数据库视图时都需要向应用程序添加代码,有时这也不是即时的,这是另一个问题。

有没有办法,可能通过使用 Meta Programming 或其他方法,我们能够查询数据库以获取视图列表并生成必要的路由和代码以 return 有效响应.

下面是代码的相关部分

namespace :api do
  namespace :v1 do
    [
      'leases',
      # a new will go in here
    ]
  end
end

class Api::V1::LeasesController < Api::V1::ApplicationController
  api :GET, '/leases', "Retrieve paginated well month data"
  param :authentication_token, String, "Token for authentication"

  def index
    result = Api::Lease.ransack(params[:q]).result.page(params[:page]).per(10000)
    render json: result.to_json
  end
end


class Api::Lease < ExternalRecord
  self.table_name = 'View_Leases' #View in External Postgres server
end

谢谢。

您可以通过给定的连接进行任意 SQL 查询

namespace :v1 do
  resources :views, only: :show
end


class ViewsController
  def show
    table_name = "View_#{params[:id].titleize}"
    offset = (params[:page].to_i || 1) * 10_000 - 10_000
    limit = 10_000
    sql = "SELECT #{table_name}.* FROM #{table_name} OFFSET #{offset} LIMIT #{limit};"
    data = ActiveRecord::Base.connection.execute(sql)
    render json: data.to_json
  end
end

但后来忘了使用搜查。 Ransack 需要一个模型,它依赖于推断的列类型将查询转换为模型本身的一系列 where、join 等。

当然,如果您制作自己的 SQL 字符串,您应该保护自己免受 SQL 注入。

如果你想保留查询的全部功能,你最好在你的应用程序和你的视图之间放置类似 Hasura 的内容,并将传入的查询转换为对 hasura 的 GraphQL 请求(它将处理为你休息)。

Is there a way, probably by using Meta Programming or something else we are able to query the database to get the list of views and generate the necessary routes and code to return a valid response.

是的,但实际实施取决于所使用的数据库。在 Postgres 上,您可以通过查询 pg_catalog.pg_views:

来获取视图列表
pg_views = Arel::Table.new('pg_catalog.pg_views')
query = pg_views.project(:schemaname, :viewname)
                .where(
                  pg_views[:schemaname].in('pg_catalog', 'information_schema').not
                )

result = ActiveRecord::Base.connection.execute(query)
# ... 

但是这里需要更改框架。视图是否一定需要对应于它自己的路线,或者您可以创建更好的 RESTful 设计吗?

例如,如果您按 year/month 列出,您可以轻松设置覆盖它的单一路线:

namespace :api do
  namespace :v1 do
    resources :leases do
      get '/leases/by_month/:year/:month', as: :by_month, action: :by_month
    end
  end
end

你能用元编程设置模型吗?

当然可以。 类 in Ruby 是 first-class 对象,您可以使用 Class.new:

创建它们
# Setup a base class for shared behavior 
class ApplicationView < ActiveRecord::Base
  self.abstract_class = true
end

str = 'Foo'
model = Class.new(ApplicationView) do |klass|
  # do your model specific thing here...
end

# Classes get their name by being assigned to a constant
ApplicationView.const_set(str, model)
ApplicationView::Foo.all # SELECT * FROM foos;  

ActiveRecord 和 ActiveModel 不太喜欢匿名 classes(classes 没有分配给常量)因为他们做了一堆基于 class 的假设姓名。这里我们将常量嵌套在 ApplicationView 中只是为了避免命名空间崩溃。

有时在库代码中使用的另一种方法是创建一个包含代码的字符串来定义 class 并对其求值。

您还可以设置查询不同 tables/views.

的单个模型

你能用元编程设置控制器和视图(如在 MVC 中)吗?

是的。但你不应该需要它。您可以简单地创建可以处理各种模型的通用控制器。请记住,控制器对应于单个模型的想法只是适用于琐碎情况的约定。