Given the answers cheops and D-side , the following has turned out:
This is a ready-made example of implementing a smart and fast search using 'stored procedures', which is what starts from migration without any problems.
# /db/migrate/20160806225544_create_searches.rb: class CreateSearches < ActiveRecord::Migration def change ActiveRecord::Base.connection.execute('DROP PROCEDURE IF EXISTS search') ActiveRecord::Base.clear_active_connections! sql = <<-SQL CREATE PROCEDURE search(IN search_data VARCHAR(255)) BEGIN DROP TABLE IF EXISTS searches; CREATE TABLE IF NOT EXISTS searches ( `article_id` INT(11), `article_title` VARCHAR(255), `article` TEXT, `article_index` VARCHAR(255), `articleable_id` INT, `articleable_type` VARCHAR(255), `article_position` INT, `article_published` INT, `texture_title` VARCHAR(255), `texture_position` INT, `texture_published` INT, `message_index` VARCHAR(255), `message_name` VARCHAR(255), `message_contact` VARCHAR(255), `message_product_id` INT, `message_date` DATETIME, `message_position` INT, `message_published` INT, `page_title` VARCHAR(255), `page_slug` VARCHAR(255), `page_menu_id` INT, `page_parent_id` INT, `page_action_template` VARCHAR(255), `page_position` INT, `page_published` INT, `product_title` VARCHAR(255), `product_price` VARCHAR(255), `product_menu_id` INT, `product_texture_id` INT, `product_view_id` INT, `product_filling_id` INT, `product_seat_count_id` INT, `product_position` INT(11), `product_published` INT(11) )ENGINE=MYISAM DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; INSERT INTO searches ( `article_id` , `article_title` , `article` , `article_index` , `articleable_id` , `articleable_type` , `article_position` , `article_published` , `texture_title` , `texture_position` , `texture_published` , `message_index` , `message_name` , `message_contact` , `message_product_id` , `message_date` , `message_position` , `message_published` , `page_title` , `page_slug` , `page_menu_id` , `page_parent_id` , `page_action_template` , `page_position` , `page_published` , `product_title` , `product_price` , `product_menu_id` , `product_texture_id` , `product_view_id` , `product_filling_id` , `product_seat_count_id`, `product_position` , `product_published` ) SELECT DISTINCT `a`.`id` as `article_id` , `a`.`title` as `article_title` , `a`.`article` as `article` , `a`.`index` as `article_index` , `a`.`articleable_id` as `articleable_id` , `a`.`articleable_type` as `articleable_type` , `a`.`position` as `article_position` , `a`.`published` as `article_published` , `t`.`title` as `texture_title` , `t`.`position` as `texture_position` , `t`.`published` as `texture_published` , `m`.`index` as `message_index` , `m`.`name` as `message_name` , `m`.`contact` as `message_contact` , `m`.`product_id` as `message_product_id` , `m`.`date` as `message_date` , `m`.`position` as `message_position` , `m`.`published` as `message_published` , `p`.`title` as `page_title` , `p`.`slug` as `page_slug` , `p`.`menu_id` as `page_menu_id` , `p`.`parent_id` as `page_parent_id` , `p`.`action_template` as `page_action_template` , `p`.`position` as `page_position` , `p`.`published` as `page_published` , `pc`.`title` as `product_title` , `pc`.`price` as `product_price` , `pc`.`menu_id` as `product_menu_id` , `pc`.`texture_id` as `product_texture_id` , `pc`.`product_view_id` as `product_view_id` , `pc`.`product_filling_id` as `product_filling_id` , `pc`.`product_seat_count_id` as `product_seat_count_id`, `pc`.`position` as `product_position` , `pc`.`published` as `product_published` FROM `articles` `a` LEFT OUTER JOIN `textures` `t` ON `a`.`articleable_id` = `t`.`id` LEFT OUTER JOIN `messages` `m` ON `a`.`articleable_id` = `m`.`id` LEFT OUTER JOIN `pages` `p` ON `a`.`articleable_id` = `p`.`id` LEFT OUTER JOIN `products` `pc` ON `a`.`articleable_id` = `pc`.`id` UNION SELECT DISTINCT `a`.`id` as `article_id` , `a`.`title` as `article_title` , `a`.`article` as `article` , `a`.`index` as `article_index` , `a`.`articleable_id` as `articleable_id` , `a`.`articleable_type` as `articleable_type` , `a`.`position` as `article_position` , `a`.`published` as `article_published` , `t`.`title` as `texture_title` , `t`.`position` as `texture_position` , `t`.`published` as `texture_published` , `m`.`index` as `message_index` , `m`.`name` as `message_name` , `m`.`contact` as `message_contact` , `m`.`product_id` as `message_product_id` , `m`.`date` as `message_date` , `m`.`position` as `message_position` , `m`.`published` as `message_published` , `p`.`title` as `page_title` , `p`.`slug` as `page_slug` , `p`.`menu_id` as `page_menu_id` , `p`.`parent_id` as `page_parent_id` , `p`.`action_template` as `page_action_template` , `p`.`position` as `page_position` , `p`.`published` as `page_published` , `pc`.`title` as `product_title` , `pc`.`price` as `product_price` , `pc`.`menu_id` as `product_menu_id` , `pc`.`texture_id` as `product_texture_id` , `pc`.`product_view_id` as `product_view_id` , `pc`.`product_filling_id` as `product_filling_id` , `pc`.`product_seat_count_id` as `product_seat_count_id`, `pc`.`position` as `product_position` , `pc`.`published` as `product_published` FROM `articles` `a` RIGHT OUTER JOIN `textures` `t` ON `a`.`articleable_id` = `t`.`id` RIGHT OUTER JOIN `messages` `m` ON `a`.`articleable_id` = `m`.`id` RIGHT OUTER JOIN `pages` `p` ON `a`.`articleable_id` = `p`.`id` RIGHT OUTER JOIN `products` `pc` ON `a`.`articleable_id` = `pc`.`id`; CREATE FULLTEXT INDEX ixFull ON searches ( `article_title`, `article` , `texture_title`, `page_title` , `product_title` ); SELECT *,MATCH( `article_title`, `article` , `texture_title`, `page_title` , `product_title` ) AGAINST (CONCAT('*',search_data,'*') IN NATURAL LANGUAGE MODE) AS coefficient FROM searches WHERE MATCH( `article_title`, `article` , `texture_title`, `page_title` , `product_title` ) AGAINST (CONCAT('*',search_data,'*') IN BOOLEAN MODE) ORDER BY coefficient DESC; ALTER table searches ENGINE = BLACKHOLE; END SQL ActiveRecord::Base.connection.execute(sql) ActiveRecord::Base.clear_active_connections! end end # /app/controllers/searches_controller.rb: class SearchesController < InheritedResources::Base def show @result = ActiveRecord::Base.connection.execute("call search('#{params[:search]}')") ActiveRecord::Base.clear_active_connections! end end