I have a rails application running on production mode, but all of the sudden this error came up today when a user tried to save a record.
I managed to store emojis (which take up 4 bytes) by following this blog post:
Rails 4, MySQL, and Emoji (
Mysql2::Error: Incorrect string value error.
)You might think that you’re safe inserting most utf8 data in to mysql when you’ve specified that the charset is
utf-8
. Sadly, however, you’d be wrong. The problem is that the utf8 character set takes up 3 bytes when stored in a VARCHAR column. Emoji characters, on the other hand, take up 4 bytes.The solution is in 2 parts:
Change the encoding of your table and fields:
ALTER TABLE `[table]` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin, MODIFY [column] VARCHAR(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
Tell the
mysql2
adapter about it:development: adapter: mysql2 database: db username: password: encoding: utf8mb4 collation: utf8mb4_unicode_ci
Hope this helps someone!
Then I had to restart my app and it worked. Please note that some emojis will work without this fix, while some won't:
You can use a migration like this to convert your tables to utf8:
class ConvertTablesToUtf8 < ActiveRecord::Migration
def change_encoding(encoding,collation)
connection = ActiveRecord::Base.connection
tables = connection.tables
dbname =connection.current_database
execute <<-SQL
ALTER DATABASE #{dbname} CHARACTER SET #{encoding} COLLATE #{collation};
SQL
tables.each do |tablename|
execute <<-SQL
ALTER TABLE #{dbname}.#{tablename} CONVERT TO CHARACTER SET #{encoding} COLLATE #{collation};
SQL
end
end
def change
reversible do |dir|
dir.up do
change_encoding('utf8','utf8_general_ci')
end
dir.down do
change_encoding('latin1','latin1_swedish_ci')
end
end
end
end
Need to change CHARACTER SET
and COLLATE
for already created database:
ALTER DATABASE databasename CHARACTER SET utf8 COLLATE utf8_unicode_ci;
Or it was necessary to create a database with pre-set parameters:
CREATE DATABASE databasename CHARACTER SET utf8 COLLATE utf8_general_ci;
Also, if you don't want to do changes in your database structure, you could opt by serializing the field in question.
class MyModel < ActiveRecord::Base
serialize :content
attr_accessible :content, :title
end
If you want to the store emoji, you need to do the following:
Create a migration (thanks @mfazekas)
class ConvertTablesToUtf8 < ActiveRecord::Migration def change_encoding(encoding,collation) connection = ActiveRecord::Base.connection tables = connection.tables dbname =connection.current_database execute <<-SQL ALTER DATABASE #{dbname} CHARACTER SET #{encoding} COLLATE #{collation}; SQL tables.each do |tablename| execute <<-SQL ALTER TABLE #{dbname}.#{tablename} CONVERT TO CHARACTER SET #{encoding} COLLATE #{collation}; SQL end end
def change reversible do |dir| dir.up do change_encoding('utf8mb4','utf8mb4_bin') end dir.down do change_encoding('latin1','latin1_swedish_ci') end end end end
Change rails charset to utf8mb4 (thanks @selvamani-p)
production: encoding: utf8mb4
References:
https://stackoverflow.com/a/39465494/1058096
https://stackoverflow.com/a/26273185/1058096
It seems like an encoding problem while getting data from database. Try adding the below to your database.yml file
encoding: utf8
Hope this solves your issue