admin管理员组

文章数量:1278825

I have a Rails application using Postgres as the database.

Postrgres does not accept strings containing null bytes (example: "a \u0000 b"). Trying to save such data leads to the following error:

ActiveRecord::StatementInvalid
PG::UntranslatableCharacter: ERROR:  unsupported Unicode escape sequence

I'd like to set up a rule that would work for all of my ActiveRecord models, ensuring that every string attribute would remove null bytes from it before saving. I'm thinking of something that could have an effect similar to the example below:

class MyModel < ApplicationRecord
  before_save :remove_null_bytes

  private

  def remove_null_bytes
    my_field.delete!("\u0000")
  end
end

But applied to every string attribute of every model without being forced to set this repeatedly.

The reason I want this to be limited to Active Record string attributes is that the application also handles binary uploads and email webhooks. These might contain legit null bytes, and I do not want these to be affected by the new rule.

I have a Rails application using Postgres as the database.

Postrgres does not accept strings containing null bytes (example: "a \u0000 b"). Trying to save such data leads to the following error:

ActiveRecord::StatementInvalid
PG::UntranslatableCharacter: ERROR:  unsupported Unicode escape sequence

I'd like to set up a rule that would work for all of my ActiveRecord models, ensuring that every string attribute would remove null bytes from it before saving. I'm thinking of something that could have an effect similar to the example below:

class MyModel < ApplicationRecord
  before_save :remove_null_bytes

  private

  def remove_null_bytes
    my_field.delete!("\u0000")
  end
end

But applied to every string attribute of every model without being forced to set this repeatedly.

The reason I want this to be limited to Active Record string attributes is that the application also handles binary uploads and email webhooks. These might contain legit null bytes, and I do not want these to be affected by the new rule.

Share Improve this question asked Feb 24 at 22:05 lmtaqlmtaq 4563 silver badges13 bronze badges 1
  • 1 You could consider patching ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting#quote_string something as simple as a prepended module defining def quote_string(s); s.delete!("\u0000"); super(s); end would likely solve the issue. – engineersmnky Commented Feb 25 at 15:01
Add a comment  | 

3 Answers 3

Reset to default 4

When you want to normalize all string type attributes on all models, then I would add this to ApplicationRecord:

class ApplicationRecord < ActiveRecord::Base
  normalizes *attribute_names, 
    with: ->(value) { value.delete("\u0000") if value.is_a?(String) }
end

Note that normalizes was introduced in Ruby on Rails 7.1 and is not available on older versions.

I'm thinking about setting something like this on ApplicationRecord:

class ApplicationRecord < ActiveRecord::Base
  before_save :remove_null_bytes

  def remove_null_bytes
    changes.keys.each do |attribute_name|
      attr_type = type_for_attribute(attribute_name).type
      send(attribute_name).delete!("\u0000") if attr_type == :string
    end
  end
end

Not sure I'm happy about the metaprogramming and the lack of readability on this approach though

Override write_attribute in ApplicationRecord to ensure that any string attributes are sanitized when assigned:

no need to add before_save method

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def write_attribute(attr_name, value)
    column = self.class.columns_hash[attr_name.to_s]

    if column&.type == :string && value.is_a?(String)
      value = value.delete("\u0000")
    end

    super(attr_name, value)
  end
end

本文标签: ruby on railsRemove null bytes for every ActiveRecord string attributesStack Overflow