我可以使用 ActiveRecord 获得以下 SQL 查询的相同输出吗?
SELECT d.title, COUNT(ep.*)
FROM posts d
LEFT JOIN comments ep
ON d.title = ep.post_title
GROUP BY d.title;
我试过Post.joins(:comments).group(:title).count('comments.*')
。
我可以使用 ActiveRecord 获得以下 SQL 查询的相同输出吗?
SELECT d.title, COUNT(ep.*)
FROM posts d
LEFT JOIN comments ep
ON d.title = ep.post_title
GROUP BY d.title;
我试过Post.joins(:comments).group(:title).count('comments.*')
。
我重温了 Ruby on Rails,玩了玩公案。我不明白为什么array[4,0]
,所以array[4,100]
返回了[]
nil
def test_slicing_arrays
array = [:peanut, :butter, :and, :jelly]
assert_equal [:peanut], array[0,1]
assert_equal [:peanut, :butter], array[0,2]
assert_equal [:and, :jelly], array[2,2]
assert_equal [:and, :jelly], array[2,20]
assert_equal [], array[4,0]
assert_equal [], array[4,100]
assert_equal nil, array[5,0]
end
我有以下parent.yml.erb:
template:
spec:
- image:
env:
- name: env_a
valueFrom:
...
- name: env_b
valueFrom:
...
- name: env_c
valueFrom:
...
- name: env_d
valueFrom:
...
我想将其提取出来env_b
并env_c
放入单独的 child.yml.erb 文件中,然后将其嵌入到 parent.yml.erb 中,我已尝试以下方法。
父级.yml.erb:
template:
spec:
- image:
env:
- name: env_a
valueFrom:
...
<%= ERB.new(File.read('child.yml.erb').gsub(/^/, ' ' * 8)).result(binding) %>
- name: env_d
valueFrom:
...
child.erb.yml:
- name: env_b
valueFrom:
...
- name: env_c
valueFrom:
...
使用以下命令渲染 parent.yml.erb 后的结果ERB.new(File.read('parent.yml.erb')).result(binding)
:
- name: env_b
valueFrom:
...
- name: env_c
valueFrom:
...
- name: env_d
valueFrom:
...
env_b
、、env_c
下面的所有内容都会渲染,但上面的所有内容<%= ERB.new(File.read('child.yml.erb').gsub(/^/, ' ' * 8)).result(binding) %>
都会被删除。我这里是不是做错了什么?
是.gsub(/^/, ' ' * 8)
为了保持相同的缩进。即使我删除了 ,问题仍然没有解决gsub
。
我正在尝试通过活动管理面板创建一条新的图书记录,但点击“创建”按钮后却无法创建。点击“创建”按钮后,会有一个包含表单数据的 POST 请求发送到 /admin/books。但它并没有返回 302 错误并重定向到图书列表,而是返回了 200 错误以及类似更新表单的内容。即使我打开控制台检查图书是否已创建,它仍然没有创建。我手动在模型中添加了“新建”和“创建”操作,现在一切正常。创建操作在其他模型中运行正常,并且只影响我的“图书”模型。
这是我的 admin/books.rb 文件中的代码
ActiveAdmin.register Book do
permit_params :title, :page_count, :book_type, :year_released, :price, :genre_id, :language_id, :author_id
# Displays the drop down menus correctly as well as all other inputs in order of my choosing
form do |show|
show.inputs "Details" do
show.input :language_id, as: :select, collection: Language.all.collect { |language|
[ language.language_short, language.id ] }
show.input :author_id, as: :select, collection: Author.all.collect { |author| [ author.full_name, author.age,
author.gender_short, author.biography, author.id ] }
show.input :title
show.input :genre_id, as: :select, collection: Genre.all.collect { |genre| [ genre.genre, genre.id ] }
show.input :book_type
show.input :year_released
show.input :price
end
show.actions
end
end
这是我的书籍模型
class Book < ApplicationRecord
# Validates that all columns are not empty
validates :title, :page_count, :book_type, :year_released, :price, presence: true
# Validates that the title is unique
validates :title, uniqueness: true
# Associations between its parent tables and child table
# has_and_belongs_to_many :genres
belongs_to :language
belongs_to :author
has_many :purchases
def self.ransackable_associations(auth_object = nil)
[ "author", "genres", "language", "purchases" ]
end
def self.ransackable_attributes(auth_object = nil)
[ "author_id", "book_type", "created_at", "genre_id", "id", "language_id", "page_count", "price", "title", "updated_at", "year_released" ]
end
end
当我使用默认的书籍表单而不是自定义表单时,genre_id 属性不会出现,并且仍然执行相同的行为(无法创建书籍并返回 POST 200)。
我正在使用 Ruby 版本 3.4.1 和 Rails 版本 8.0.2。
这些是创建新书籍时的服务器日志
Started POST "/admin/books" for 127.0.0.1 at 2025-04-10 14:45:29 -0500
Processing by Admin::BooksController#create as HTML
Parameters: {"authenticity_token" => "[FILTERED]", "book" => {"language_id" => "3", "author_id" => "6", "title" => "Captain Underpants", "genre_id" => "8", "book_type" => "Physical", "year_released" => "1997", "price" => "9.99"}, "commit" => "Create Book"}
AdminUser Load (0.2ms) SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = 3 ORDER BY "admin_users"."id" ASC LIMIT 1 /*action='create',application='ECommerce',controller='books'*/
TRANSACTION (0.1ms) BEGIN immediate TRANSACTION /*action='create',application='ECommerce',controller='books'*/
Book Exists? (2.9ms) SELECT 1 AS one FROM "books" WHERE "books"."title" = 'Captain Underpants' LIMIT 1 /*action='create',application='ECommerce',controller='books'*/
Language Load (0.3ms) SELECT "languages".* FROM "languages" WHERE "languages"."id" = 3 LIMIT 1 /*action='create',application='ECommerce',controller='books'*/
Author Load (0.1ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = 6 LIMIT 1 /*action='create',application='ECommerce',controller='books'*/
TRANSACTION (0.1ms) ROLLBACK TRANSACTION /*action='create',application='ECommerce',controller='books'*/
Rendering /home/segern/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/activeadmin-3.3.0/app/views/active_admin/resource/new.html.arb
Language Load (0.2ms) SELECT "languages".* FROM "languages" /*action='create',application='ECommerce',controller='books'*/
↳ app/admin/books.rb:7:in 'Enumerable#collect'
Author Load (0.7ms) SELECT "authors".* FROM "authors" /*action='create',application='ECommerce',controller='books'*/
↳ app/admin/books.rb:9:in 'Enumerable#collect'
Genre Load (0.3ms) SELECT "genres".* FROM "genres" /*action='create',application='ECommerce',controller='books'*/
↳ app/admin/books.rb:12:in 'Enumerable#collect'
Rendered /home/segern/.rbenv/versions/3.4.1/lib/ruby/gems/3.4.0/gems/activeadmin-3.3.0/app/views/active_admin/resource/new.html.arb (Duration: 57.9ms | GC: 1.0ms)
Completed 200 OK in 89ms (Views: 58.0ms | ActiveRecord: 4.5ms (7 queries, 0 cached) | GC: 1.7ms)
Started GET "/favicon.ico" for 127.0.0.1 at 2025-04-10 14:45:29 -0500
ActionController::RoutingError (No route matches [GET] "/favicon.ico"):
以下 ruby 方法预计返回一个数组或 nil,具体取决于 api 调用是否成功。
# @return [Array or nil] - but should not throw error if anything fails
def fetch_coords_from_api
api_url = "some_api_url"
params = { api_key: ENV["API_KEY"] }
response = ApiClient.new(api_url, params).get
return unless response
json = JSON.parse(response.body)
return unless json.is_a?(Hash) && json["result"]
addresses = json["result"]
return unless addresses.is_a?(Array) && !addresses.empty?
address = addresses.find { |add| add["zip"] == zip }
return unless address&.key?("latitude") && address&.key?("longitude")
[ address["latitude"], address["longitude"] ]
end
一些背景:该方法是尝试几种检索坐标的方法的类的一部分(如果一种方法失败,我们将转到下一种方法)。
这虽然按预期工作,但似乎也违反了一些最佳实践和惯例(关于对无效状态进行多次检查)。有人能建议一种更健壮/高效/常规/美观的方式来处理这种情况吗?
当我尝试以生产模式启动服务器时出现此错误
=> Booting Puma
=> Rails 8.0.1 application starting in production
=> Run `bin/rails server --help` for more startup options
[dotenv] Loaded .env
Exiting
C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/cref.rb:63:in `const_get': uninitialized constant Openai::Openai (NameError)
@mod.const_get(@cname, false)
^^^^^^^^^^
Did you mean? OpenAI
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/cref.rb:63:in `get'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:173:in `block in actual_eager_load_dir'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/helpers.rb:47:in `block in ls'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/helpers.rb:25:in `each'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/helpers.rb:25:in `ls'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:168:in `actual_eager_load_dir'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:17:in `block (2 levels) in eager_load'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:16:in `each'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:16:in `block in eager_load'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:10:in `synchronize'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/eager_load.rb:10:in `eager_load'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader.rb:430:in `block in eager_load_all'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader.rb:428:in `each'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/zeitwerk-2.7.2/lib/zeitwerk/loader.rb:428:in `eager_load_all'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/application/finisher.rb:79:in `block in <module:Finisher>'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:32:in `instance_exec'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:32:in `run'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:61:in `block in run_initializers'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:231:in `block in tsort_each'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:353:in `block (2 levels) in each_strongly_connected_component'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:434:in `each_strongly_connected_component_from'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:352:in `block in each_strongly_connected_component'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:350:in `each'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:350:in `call'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:350:in `each_strongly_connected_component'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:229:in `tsort_each'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/tsort.rb:208:in `tsort_each'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/initializable.rb:60:in `run_initializers'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/application.rb:440:in `initialize!'
from D:/PROGRAMMING/RUBY/addmemore_backend/config/environment.rb:5:in `<main>'
from config.ru:3:in `require_relative'
from config.ru:3:in `block (2 levels) in <main>'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:108:in `eval'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:108:in `new_from_string'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:97:in `load_file'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rack-3.1.8/lib/rack/builder.rb:67:in `parse_file'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:354:in `build_app_and_options_from_config'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:263:in `app'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:424:in `wrapped_app'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:326:in `block in start'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:382:in `handle_profiling'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/rackup-2.2.1/lib/rackup/server.rb:325:in `start'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands/server/server_command.rb:38:in `start'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands/server/server_command.rb:145:in `block in perform'
from <internal:kernel>:90:in `tap'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands/server/server_command.rb:136:in `perform'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/thor-1.3.2/lib/thor/command.rb:28:in `run'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/thor-1.3.2/lib/thor/invocation.rb:127:in `invoke_command'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command/base.rb:178:in `invoke_command'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/thor-1.3.2/lib/thor.rb:538:in `dispatch'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command/base.rb:73:in `perform'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command.rb:65:in `block in invoke'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command.rb:143:in `with_argv'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/command.rb:63:in `invoke'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/railties-8.0.1/lib/rails/commands.rb:18:in `<main>'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/bundled_gems.rb:69:in `require'
from D:/APPS/Ruby33-x64/lib/ruby/3.3.0/bundled_gems.rb:69:in `block (2 levels) in replace_require'
from C:/Users/tolia/.local/share/gem/ruby/3.3.0/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
from D:/PROGRAMMING/RUBY/addmemore_backend/bin/rails:4:in `<main>'
我在文件夹openai.rb
中app/services/openai/
需要“net/http”需要“uri”需要“json”
class OpenAI
def initialize(api_key)
@api_key = api_key
end
def generate_comments(number_of_comments, post_description, customer_query)
# some code ...
end
end
我也将其包含在 application_controller.rb 中
require_relative "../services/openai/openai"
以前我通过重命名文件夹、模块和类解决了这个问题,但现在它变得太烦人了,因为类被命名OpenAI
,但 rails 试图找到Openai
在查询和以 XML 响应的 API 时,在控制台中跟踪虚构的数据时会出现一个有趣的元素,但布局不是:
<address>SUTTER 10821
1032 LALALAND</address>
httparty
解析由ruby gem运行。
字符串中的换行符保存为\n
文本数据类型。然而,在 rails 中使用 进行渲染时.html_safe
,不会渲染新行。
在写入记录时处理地址属性的最佳方法是什么?
我正在努力让计数器缓存在 has_one :through 上工作,但遇到了一些奇怪的行为。我想在模型上有一个 counter_cache ,用于缓存关联(通过模型)Company
的数量。Location
BusinessUnit
对象:
class Company < ApplicationRecord
has_many :business_units, class_name: :BusinessUnit, dependent: :destroy
has_many :locations, through: :business_units, dependent: :destroy, counter_cache: :locations_count
end
class BusinessUnit < ApplicationRecord
belongs_to :company, counter_cache: :locations_count
has_many :locations, dependent: :destroy
end
class Location < ApplicationRecord
belongs_to :business_unit
has_one :company, through: :business_unit
end
架构:
ActiveRecord::Schema[7.1].define(version: 2025_04_03_203549) do
enable_extension "plpgsql"
create_table "business_units", force: :cascade do |t|
t.string "name"
t.bigint "company_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["company_id"], name: "index_business_units_on_company_id"
end
create_table "companies", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "locations_count", default: 0, null: false
end
create_table "locations", force: :cascade do |t|
t.string "name"
t.bigint "business_unit_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["business_unit_id"], name: "index_locations_on_business_unit_id"
end
add_foreign_key "business_units", "companies"
add_foreign_key "locations", "business_units"
end
根据这些 SO 答案 ( 1、2 ),我的理解是这应该可行。关于 Rails 如何自动知道引用位置计数,文档并不完善,而且有点违反直觉,但实际上它似乎确实有一些 Rails 魔力,Company.reset_counters(1, :locations)
正确调用会将计数器设置为匹配位置数。
但是,当添加或删除位置时,计数器不会自动更新(增加或减少),并且如果更新具有 N 个位置的业务单元并将其分配给另一家公司,则计数器只会增加/减少 1(而不是预期的 N 个位置)。此行为在 Rails 8.0.1 和 7.1.3(我无意中用它们来构建我的 MRE)中都存在。
我是否遗漏了一些明显可以使 counter_cache 正常工作的东西?
我想创建一个可以在任何页面中使用的搜索栏,以便查找电影数据库中的项目。我的搜索栏仅在我已经在电影索引页中时才起作用,但它在任何其他页面中都不起作用,它只会重新加载当前视图并搜索路径。提交搜索后,如何重定向到电影索引页?
<form class="d-flex">
<%= form_tag movies_path, method: :get do %>
<%= text_field_tag :search, params[:search], class:"form-control me-2", placeholder:"Search" %>
<%= submit_tag "Search", :title => nil, class:"btn btn-outline-primary" %>
<% end %>
</form>
我有一个模型Entity
,可以有offers
和invoices
。用户可以创建自定义数字格式来显示发票号码。例如,内部发票号码23
可以变成2025INV00000023
或类似的。现在,对于offers
,我们需要能够使用不同的数字格式。23
可能会变成2025OFF00000023
。
我通过创建一个类来实现这一点NumberFormat
,用户可以通过多种方式配置数字格式。数字格式与实体相关联,因为出于税务/会计目的,实体的所有发票都需要具有统一/一致的编号。
我的Entity
模型开始如下:
class Entity < ApplicationRecord
has_many :invoices, dependent: :restrict_with_error
has_many :offers, dependent: :restrict_with_error
还有一些不相关的has_many
belongs_to :invoice_number_format, class_name: 'NumberFormat'
belongs_to :offer_number_format, class_name: 'NumberFormat'
现在我的NumberFormat
类需要有belongs_to
关系的另一端。但我不确定加倍是否是正确的方法,以防止dependent: :restrict_with_error
用户删除仍在使用的数字格式。VSCode 的自动格式化程序只会在保存时删除第二个。我当然可以保存而不进行格式化(并且在编辑此文件时要非常小心,不要忘记),经过初步测试后,它似乎有效,但我想知道我的方法是否不理想?
has_many :entities, inverse_of: :invoice_number_format,
dependent: :restrict_with_error
# This line gets deleted on save
has_many :entities, inverse_of: :offer_number_format,
dependent: :restrict_with_error