{"id":1404,"date":"2025-03-24T08:52:15","date_gmt":"2025-03-23T23:52:15","guid":{"rendered":"https:\/\/dexall.co.jp\/articles\/?p=1404"},"modified":"2025-03-24T08:52:15","modified_gmt":"2025-03-23T23:52:15","slug":"rails%e5%88%9d%e5%bf%83%e8%80%85%e3%81%8b%e3%82%89%e3%83%97%e3%83%ad%e3%83%95%e3%82%a7%e3%83%83%e3%82%b7%e3%83%a7%e3%83%8a%e3%83%ab%e3%81%b8%ef%bc%9a%e5%ae%9f%e8%b7%b5%e3%81%a7%e5%ad%a6%e3%81%b6","status":"publish","type":"post","link":"https:\/\/dexall.co.jp\/articles\/?p=1404","title":{"rendered":"Rails\u521d\u5fc3\u8005\u304b\u3089\u30d7\u30ed\u30d5\u30a7\u30c3\u30b7\u30e7\u30ca\u30eb\u3078\uff1a\u5b9f\u8df5\u3067\u5b66\u3076\u7a76\u6975\u306eRuby on Rails\u5b8c\u5168\u30ac\u30a4\u30c92024"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\" id=\"i-0\">Ruby on Rails\u306e\u57fa\u790e\u77e5\u8b58<\/h1>\n\n\n\n<div class=\"toc\"><br \/>\n<b>Warning<\/b>:  Undefined array key \"is_admin\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>116<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_category_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>121<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>128<\/b><br \/>\n    <div id=\"toc_container\" class=\"sgb-toc--bullets js-smooth-scroll\" data-dialog-title=\"\u76ee\u6b21\">\n      <p class=\"toc_title\">\u76ee\u6b21 <\/p>\n      <ul class=\"toc_list\">  <li class=\"first\">    <a href=\"#i-0\">Ruby on Rails\u306e\u57fa\u790e\u77e5\u8b58<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-1\">\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u306e\u7279\u5fb4\u3068\u5f37\u307f<\/a>      <\/li>      <li>        <a href=\"#i-2\">\u958b\u767a\u74b0\u5883\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u624b\u9806<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-6\">MVC\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u306e\u5b9f\u8df5\u7684\u306a\u7406\u89e3<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-11\">\u5b9f\u8df5\u7684\u306aRails\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u30ac\u30a4\u30c9<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-12\">\u30e2\u30c7\u30eb\u8a2d\u8a08\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/a>      <\/li>      <li>        <a href=\"#i-16\">\u52b9\u7387\u7684\u306a\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u8a2d\u5b9a\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-19\">\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u3067\u306e\u30d3\u30b8\u30cd\u30b9\u30ed\u30b8\u30c3\u30af\u5b9f\u88c5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-23\">\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u8a2d\u8a08\u3068\u64cd\u4f5c<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-24\">ActiveRecord\u3092\u4f7f\u3044\u3053\u306a\u3059\u30c6\u30af\u30cb\u30c3\u30af<\/a>      <\/li>      <li>        <a href=\"#i-28\">\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u52b9\u679c\u7684\u306a\u7ba1\u7406\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-32\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u8003\u616e\u3057\u305f\u30af\u30a8\u30ea\u306e\u66f8\u304d\u65b9<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-36\">\u30c6\u30b9\u30c8\u99c6\u52d5\u958b\u767a\u306e\u5b9f\u8df5<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-37\">RSpec\u306b\u3088\u308b\u52b9\u7387\u7684\u306a\u30c6\u30b9\u30c8\u8a2d\u8a08<\/a>      <\/li>      <li>        <a href=\"#i-40\">\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9\u306e\u4f5c\u6210\u3068\u5b9f\u884c\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-43\">\u30e2\u30c3\u30af\u3068\u30b9\u30bf\u30d6\u306e\u6d3b\u7528\u30c6\u30af\u30cb\u30c3\u30af<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-47\">\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u306e\u5b9f\u88c5<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-48\">\u4e00\u822c\u7684\u306a\u8106\u5f31\u6027\u3078\u306e\u5bfe\u51e6\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-52\">\u8a8d\u8a3c\u30fb\u8a8d\u53ef\u306e\u5b9f\u88c5\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-55\">\u30bb\u30ad\u30e5\u30a2\u306aAPI\u958b\u767a\u306e\u624b\u6cd5<\/a>      <\/li>    <\/ul>  <\/li>  <li class=\"last\">    <a href=\"#i-59\">\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u3068\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-60\">\u672c\u756a\u74b0\u5883\u3078\u306e\u30c7\u30d7\u30ed\u30a4\u624b\u9806<\/a>      <\/li>      <li>        <a href=\"#i-64\">\u7d99\u7d9a\u7684\u30a4\u30f3\u30c6\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u69cb\u7bc9\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-66\">\u52b9\u7387\u7684\u306a\u30c7\u30d0\u30c3\u30b0\u3068\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0<\/a>      <\/li>    <\/ul>  <\/li><\/ul>\n      <a href=\"#\" class=\"sgb-toc-button js-toc-button\" rel=\"nofollow\" data-open-dialog=\"true\"><i class=\"fa fa-list\"><\/i><span class=\"sgb-toc-button__text\">\u76ee\u6b21\u3078<\/span><\/a>\n    <\/div><\/div><h2 class=\"wp-block-heading\" id=\"i-1\">\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u306e\u7279\u5fb4\u3068\u5f37\u307f<\/h2>\n\n\n\n<p>Ruby on Rails\u306f\u3001Web\u958b\u767a\u306e\u52b9\u7387\u6027\u3068\u751f\u7523\u6027\u3092\u6700\u5927\u9650\u306b\u9ad8\u3081\u308b\u305f\u3081\u306e\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3059\u3002\u4ee5\u4e0b\u306e\u4e3b\u8981\u306a\u7279\u5fb4\u3068\u5f37\u307f\u306b\u3088\u308a\u3001\u591a\u304f\u306e\u958b\u767a\u8005\u304b\u3089\u652f\u6301\u3055\u308c\u3066\u3044\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Convention over Configuration\uff08CoC\uff09<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8a2d\u5b9a\u3088\u308a\u898f\u7d04\u3092\u91cd\u8996\u3059\u308b\u601d\u60f3<\/li>\n\n\n\n<li>\u6a19\u6e96\u7684\u306a\u547d\u540d\u898f\u5247\u3084\u8a2d\u5b9a\u306b\u5f93\u3046\u3053\u3068\u3067\u3001\u6700\u5c0f\u9650\u306e\u30b3\u30fc\u30c9\u3067\u958b\u767a\u53ef\u80fd<\/li>\n\n\n\n<li>\u4f8b\uff1a\u30e2\u30c7\u30eb\u540d\u304c\u5358\u6570\u5f62\u306a\u3089\u3001\u5bfe\u5fdc\u3059\u308b\u30c6\u30fc\u30d6\u30eb\u540d\u306f\u8907\u6570\u5f62<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Don\u2019t Repeat Yourself\uff08DRY\uff09<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30b3\u30fc\u30c9\u306e\u91cd\u8907\u3092\u907f\u3051\u3001\u4fdd\u5b88\u6027\u3092\u5411\u4e0a<\/li>\n\n\n\n<li>\u5171\u901a\u6a5f\u80fd\u306e\u518d\u5229\u7528\u3092\u4fc3\u9032<\/li>\n\n\n\n<li>\u5909\u66f4\u7b87\u6240\u3092\u6700\u5c0f\u9650\u306b\u6291\u3048\u308b<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>ActiveRecord\u306b\u3088\u308b\u76f4\u611f\u7684\u306a\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u64cd\u4f5c<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u30c7\u30fc\u30bf\u306e\u53d6\u5f97\u3068\u4f5c\u6210\u304c\u76f4\u611f\u7684\nuser = User.find(1)\nnew_user = User.create(name: \"John\", email: \"john@example.com\")\n\n# \u95a2\u9023\u4ed8\u3051\u3082\u7c21\u6f54\u306b\u8a18\u8ff0\u53ef\u80fd\nclass User &lt; ApplicationRecord\n  has_many :posts\n  has_one :profile\nend<\/pre>\n\n\n\n<ol start=\"4\" class=\"wp-block-list\">\n<li><strong>\u8c4a\u5bcc\u306aGem\uff08\u30e9\u30a4\u30d6\u30e9\u30ea\uff09\u30a8\u30b3\u30b7\u30b9\u30c6\u30e0<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8a8d\u8a3c\uff08Devise\uff09<\/li>\n\n\n\n<li>\u7ba1\u7406\u753b\u9762\uff08ActiveAdmin\uff09<\/li>\n\n\n\n<li>\u30d5\u30a1\u30a4\u30eb\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\uff08CarrierWave\uff09<\/li>\n\n\n\n<li>API\u958b\u767a\uff08Grape\uff09<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-2\">\u958b\u767a\u74b0\u5883\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u624b\u9806<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-3\">1. \u5fc5\u8981\u306a\u30c4\u30fc\u30eb\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Ruby\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\uff08rbenv\u3092\u4f7f\u7528\uff09\nbrew install rbenv\nrbenv init\nrbenv install 3.2.2\nrbenv global 3.2.2\n\n# Rails\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\ngem install rails -v 7.1.2\n\n# Node.js\u3068Yarn\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\nbrew install node\nnpm install -g yarn<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-4\">2. \u65b0\u898f\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4f5c\u6210<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># PostgreSQL\u3092\u4f7f\u7528\u3059\u308b\u65b0\u898fRails\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u4f5c\u6210\nrails new myapp --database=postgresql\n\n# \u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3078\u79fb\u52d5\ncd myapp\n\n# \u4f9d\u5b58\u95a2\u4fc2\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\nbundle install<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-5\">3. \u958b\u767a\u30b5\u30fc\u30d0\u30fc\u306e\u8d77\u52d5<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u4f5c\u6210\u3068\u521d\u671f\u5316\nrails db:create\nrails db:migrate\n\n# \u958b\u767a\u30b5\u30fc\u30d0\u30fc\u306e\u8d77\u52d5\nrails server<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-6\">MVC\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3\u306e\u5b9f\u8df5\u7684\u306a\u7406\u89e3<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-7\">Model\uff08\u30e2\u30c7\u30eb\uff09<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30d3\u30b8\u30cd\u30b9\u30ed\u30b8\u30c3\u30af\u3068\u30c7\u30fc\u30bf\u306e\u7ba1\u7406\u3092\u62c5\u5f53<\/li>\n\n\n\n<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3068\u306e\u3084\u308a\u53d6\u308a\u3092\u884c\u3046<\/li>\n\n\n\n<li>\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u3084\u30a2\u30bd\u30b7\u30a8\u30fc\u30b7\u30e7\u30f3\u3092\u5b9a\u7fa9<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/models\/article.rb\nclass Article &lt; ApplicationRecord\n  belongs_to :user\n  has_many :comments\n\n  validates :title, presence: true\n  validates :content, length: { minimum: 10 }\n\n  # \u30ab\u30b9\u30bf\u30e0\u30e1\u30bd\u30c3\u30c9\u306e\u4f8b\n  def self.published\n    where(status: 'published')\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-8\">View\uff08\u30d3\u30e5\u30fc\uff09<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30e6\u30fc\u30b6\u30fc\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u306e\u8868\u793a\u3092\u62c5\u5f53<\/li>\n\n\n\n<li>ERB\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066HTML\u751f\u6210<\/li>\n\n\n\n<li>\u30d1\u30fc\u30b7\u30e3\u30eb\u3092\u6d3b\u7528\u3057\u3066\u518d\u5229\u7528\u6027\u3092\u9ad8\u3081\u308b<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- app\/views\/articles\/index.html.erb --&gt;\n&lt;h1&gt;\u8a18\u4e8b\u4e00\u89a7&lt;\/h1&gt;\n\n&lt;% @articles.each do |article| %&gt;\n  &lt;div class=\"article\"&gt;\n    &lt;h2&gt;&lt;%= article.title %&gt;&lt;\/h2&gt;\n    &lt;p&gt;&lt;%= truncate(article.content, length: 100) %&gt;&lt;\/p&gt;\n    &lt;%= link_to '\u8a73\u7d30\u3092\u898b\u308b', article_path(article) %&gt;\n  &lt;\/div&gt;\n&lt;% end %&gt;\n\n&lt;%= render 'shared\/pagination' %&gt;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-9\">Controller\uff08\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\uff09<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30e2\u30c7\u30eb\u3068\u30d3\u30e5\u30fc\u306e\u6a4b\u6e21\u3057\u5f79<\/li>\n\n\n\n<li>\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u51e6\u7406\u3068\u30ec\u30b9\u30dd\u30f3\u30b9\u306e\u751f\u6210<\/li>\n\n\n\n<li>\u30d3\u30b8\u30cd\u30b9\u30ed\u30b8\u30c3\u30af\u306e\u7d44\u307f\u7acb\u3066<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/controllers\/articles_controller.rb\nclass ArticlesController &lt; ApplicationController\n  before_action :set_article, only: [:show, :edit, :update, :destroy]\n\n  def index\n    @articles = Article.published.page(params[:page])\n  end\n\n  def show\n    @comments = @article.comments.includes(:user)\n  end\n\n  def create\n    @article = current_user.articles.build(article_params)\n\n    if @article.save\n      redirect_to @article, notice: '\u8a18\u4e8b\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f'\n    else\n      render :new\n    end\n  end\n\n  private\n\n  def set_article\n    @article = Article.find(params[:id])\n  end\n\n  def article_params\n    params.require(:article).permit(:title, :content)\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-10\">MVC\u306e\u76f8\u4e92\u4f5c\u7528<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u6d41\u308c<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30d6\u30e9\u30a6\u30b6\u304b\u3089\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u304cRouter\u3067\u89e3\u6790\u3055\u308c\u308b<\/li>\n\n\n\n<li>\u9069\u5207\u306aController\u30a2\u30af\u30b7\u30e7\u30f3\u306b\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0<\/li>\n\n\n\n<li>Controller\u304cModel\u304b\u3089\u30c7\u30fc\u30bf\u3092\u53d6\u5f97<\/li>\n\n\n\n<li>View\u3067HTML\u3092\u751f\u6210\u3057\u3066\u30ec\u30b9\u30dd\u30f3\u30b9<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c7\u30fc\u30bf\u306e\u6d41\u308c<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Model\u304cDB\u304b\u3089\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u30fb\u4fdd\u5b58<\/li>\n\n\n\n<li>Controller\u304cModel\u306e\u30c7\u30fc\u30bf\u3092View\u306b\u53d7\u3051\u6e21\u3057<\/li>\n\n\n\n<li>View\u304c\u30c7\u30fc\u30bf\u3092HTML\u3068\u3057\u3066\u63cf\u753b<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u306e\u57fa\u790e\u7684\u306a\u69cb\u9020\u3092\u7406\u89e3\u3059\u308b\u3053\u3068\u3067\u3001Rails\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u958b\u767a\u52b9\u7387\u304c\u5927\u304d\u304f\u5411\u4e0a\u3057\u307e\u3059\u3002\u307e\u305f\u3001\u9069\u5207\u306a\u8cac\u52d9\u5206\u96e2\u306b\u3088\u308a\u3001\u4fdd\u5b88\u6027\u306e\u9ad8\u3044\u30b3\u30fc\u30c9\u30d9\u30fc\u30b9\u3092\u7dad\u6301\u3059\u308b\u3053\u3068\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"i-11\">\u5b9f\u8df5\u7684\u306aRails\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u30ac\u30a4\u30c9<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-12\">\u30e2\u30c7\u30eb\u8a2d\u8a08\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-13\">1. \u9069\u5207\u306a\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class User &lt; ApplicationRecord\n  # \u5fc5\u9808\u9805\u76ee\u306e\u691c\u8a3c\n  validates :email, presence: true, uniqueness: { case_sensitive: false }\n  validates :username, presence: true, length: { in: 3..20 }\n\n  # \u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u306e\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u691c\u8a3c\n  validates :email, format: { \n    with: URI::MailTo::EMAIL_REGEXP,\n    message: \"\u306f\u6709\u52b9\u306a\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u3067\u306f\u3042\u308a\u307e\u305b\u3093\"\n  }\n\n  # \u30ab\u30b9\u30bf\u30e0\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\n  validate :password_complexity\n\n  private\n\n  def password_complexity\n    return if password.blank?\n    unless password.match?(\/^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$\/)\n      errors.add :password, '\u306f\u5c11\u306a\u304f\u3068\u30828\u6587\u5b57\u3067\u3001\u6587\u5b57\u3068\u6570\u5b57\u3092\u542b\u3080\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059'\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-14\">2. \u30a2\u30bd\u30b7\u30a8\u30fc\u30b7\u30e7\u30f3\u306e\u9069\u5207\u306a\u8a2d\u8a08<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class Post &lt; ApplicationRecord\n  # \u57fa\u672c\u7684\u306a\u95a2\u9023\u4ed8\u3051\n  belongs_to :user\n  has_many :comments, dependent: :destroy\n  has_many :likes\n  has_many :liking_users, through: :likes, source: :user\n\n  # \u30dd\u30ea\u30e2\u30fc\u30d5\u30a3\u30c3\u30af\u95a2\u9023\u4ed8\u3051\n  has_many :attachments, as: :attachable\n\n  # \u30b9\u30b3\u30fc\u30d7\u3092\u4f7f\u7528\u3057\u305f\u95a2\u9023\u4ed8\u3051\u306e\u5236\u5fa1\n  has_many :approved_comments, -&gt; { where(status: 'approved') }, class_name: 'Comment'\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-15\">3. \u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u306e\u52b9\u679c\u7684\u306a\u4f7f\u7528<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class Order &lt; ApplicationRecord\n  before_validation :normalize_phone_number\n  after_create :send_confirmation_email\n  before_save :calculate_total\n\n  private\n\n  def normalize_phone_number\n    self.phone = phone.gsub(\/[^\\d]\/, '') if phone.present?\n  end\n\n  def send_confirmation_email\n    OrderMailer.confirmation(self).deliver_later\n  end\n\n  def calculate_total\n    self.total = order_items.sum { |item| item.price * item.quantity }\n  end\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-16\">\u52b9\u7387\u7684\u306a\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u8a2d\u5b9a\u65b9\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-17\">1. RESTful\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u306e\u57fa\u672c<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Rails.application.routes.draw do\n  # \u57fa\u672c\u7684\u306a\u30ea\u30bd\u30fc\u30b9\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\n  resources :posts do\n    resources :comments, shallow: true\n  end\n\n  # \u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u8ffd\u52a0\n  resources :users do\n    member do\n      patch :activate\n      patch :deactivate\n    end\n\n    collection do\n      get :search\n    end\n  end\n\n  # \u540d\u524d\u4ed8\u304d\u30eb\u30fc\u30c8\n  get 'dashboard', to: 'dashboard#index', as: :dashboard\n\n  # API\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\n  namespace :api do\n    namespace :v1 do\n      resources :posts, only: [:index, :show, :create]\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-18\">2. \u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u306e\u6700\u9069\u5316<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Rails.application.routes.draw do\n  # \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u8003\u616e\u3057\u305f\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\n  resources :posts, only: [:index, :show] do\n    resources :comments, only: [:create, :destroy]\n  end\n\n  # \u5236\u7d04\u4ed8\u304d\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\n  constraints(SubdomainRouteConstraint.new) do\n    resources :organizations\n  end\n\n  # \u30ab\u30b9\u30bf\u30e0\u30d1\u30e9\u30e1\u30fc\u30bf\u5236\u7d04\n  get 'users\/:id', to: 'users#show', \n    constraints: { id: \/[A-Za-z0-9\\.]+\/ }\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-19\">\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u3067\u306e\u30d3\u30b8\u30cd\u30b9\u30ed\u30b8\u30c3\u30af\u5b9f\u88c5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-20\">1. \u30b5\u30fc\u30d3\u30b9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u6d3b\u7528<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/services\/user_registration_service.rb\nclass UserRegistrationService\n  def initialize(params)\n    @params = params\n  end\n\n  def execute\n    user = User.new(@params)\n    if user.save\n      setup_user_profile(user)\n      send_welcome_email(user)\n      { success: true, user: user }\n    else\n      { success: false, errors: user.errors }\n    end\n  end\n\n  private\n\n  def setup_user_profile(user)\n    user.create_profile!(default_profile_params)\n  end\n\n  def send_welcome_email(user)\n    UserMailer.welcome(user).deliver_later\n  end\n\n  def default_profile_params\n    { visibility: 'public', theme: 'light' }\n  end\nend\n\n# app\/controllers\/users_controller.rb\nclass UsersController &lt; ApplicationController\n  def create\n    result = UserRegistrationService.new(user_params).execute\n    if result[:success]\n      redirect_to user_path(result[:user]), notice: '\u767b\u9332\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f'\n    else\n      @user = User.new\n      @user.errors.merge!(result[:errors])\n      render :new\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-21\">2. \u52b9\u7387\u7684\u306a\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u8a2d\u8a08<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class ArticlesController &lt; ApplicationController\n  before_action :set_article, only: [:show, :edit, :update, :destroy]\n  before_action :authorize_article, only: [:edit, :update, :destroy]\n\n  def index\n    @articles = Article.includes(:author, :categories)\n                      .published\n                      .page(params[:page])\n  end\n\n  def create\n    @article = current_user.articles.build(article_params)\n\n    respond_to do |format|\n      if @article.save\n        format.html { redirect_to @article, notice: '\u8a18\u4e8b\u304c\u4f5c\u6210\u3055\u308c\u307e\u3057\u305f' }\n        format.json { render :show, status: :created }\n      else\n        format.html { render :new }\n        format.json { render json: @article.errors, status: :unprocessable_entity }\n      end\n    end\n  end\n\n  private\n\n  def set_article\n    @article = Article.find(params[:id])\n  end\n\n  def authorize_article\n    authorize @article\n  end\n\n  def article_params\n    params.require(:article)\n          .permit(:title, :content, :status, category_ids: [])\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-22\">3. \u5171\u901a\u6a5f\u80fd\u306e\u30e2\u30b8\u30e5\u30fc\u30eb\u5316<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/controllers\/concerns\/error_handling.rb\nmodule ErrorHandling\n  extend ActiveSupport::Concern\n\n  included do\n    rescue_from ActiveRecord::RecordNotFound, with: :not_found\n    rescue_from ActionController::ParameterMissing, with: :bad_request\n    rescue_from Pundit::NotAuthorizedError, with: :forbidden\n  end\n\n  private\n\n  def not_found\n    respond_to do |format|\n      format.html { render 'errors\/not_found', status: :not_found }\n      format.json { render json: { error: 'Resource not found' }, status: :not_found }\n    end\n  end\n\n  def bad_request\n    respond_to do |format|\n      format.html { render 'errors\/bad_request', status: :bad_request }\n      format.json { render json: { error: 'Invalid parameters' }, status: :bad_request }\n    end\n  end\n\n  def forbidden\n    respond_to do |format|\n      format.html { render 'errors\/forbidden', status: :forbidden }\n      format.json { render json: { error: 'Access denied' }, status: :forbidden }\n    end\n  end\nend\n\n# \u4f7f\u7528\u4f8b\nclass ApplicationController &lt; ActionController::Base\n  include ErrorHandling\nend<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u3092\u5b9f\u8df5\u3059\u308b\u3053\u3068\u3067\u3001\u4fdd\u5b88\u6027\u304c\u9ad8\u304f\u3001\u30b9\u30b1\u30fc\u30e9\u30d6\u30eb\u306aRails\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u958b\u767a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u5404\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u8cac\u52d9\u3092\u660e\u78ba\u306b\u5206\u96e2\u3057\u3001\u9069\u5207\u306a\u8a2d\u8a08\u30d1\u30bf\u30fc\u30f3\u3092\u63a1\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u9577\u671f\u7684\u306a\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u6027\u3082\u5411\u4e0a\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"i-23\">\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u8a2d\u8a08\u3068\u64cd\u4f5c<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-24\">ActiveRecord\u3092\u4f7f\u3044\u3053\u306a\u3059\u30c6\u30af\u30cb\u30c3\u30af<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-25\">1. \u9ad8\u5ea6\u306a\u30af\u30a8\u30ea\u30e1\u30bd\u30c3\u30c9<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class User &lt; ApplicationRecord\n  # \u30b9\u30b3\u30fc\u30d7\u3092\u4f7f\u7528\u3057\u305f\u8907\u96d1\u306a\u30af\u30a8\u30ea\u306e\u5b9a\u7fa9\n  scope :active_this_month, -&gt; { \n    where('last_login_at &gt;= ?', Time.current.beginning_of_month) \n  }\n\n  scope :with_complete_profile, -&gt; {\n    joins(:profile)\n      .where.not(profiles: { bio: nil })\n      .where.not(profiles: { avatar_url: nil })\n  }\n\n  # \u8907\u96d1\u306a\u6761\u4ef6\u3092\u7d44\u307f\u5408\u308f\u305b\u305f\u691c\u7d22\n  def self.search(query)\n    where('email LIKE :query OR username LIKE :query', query: \"%#{query}%\")\n      .or(\n        where(id: Profile.where('bio LIKE :query', query: \"%#{query}%\").select(:user_id))\n      )\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-26\">2. \u95a2\u9023\u30c6\u30fc\u30d6\u30eb\u306e\u52b9\u7387\u7684\u306a\u7d50\u5408<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class Post &lt; ApplicationRecord\n  # EAGER\u30ed\u30fc\u30c7\u30a3\u30f3\u30b0\u306e\u6d3b\u7528\n  scope :with_details, -&gt; {\n    includes(:author, :categories, comments: :user)\n  }\n\n  # \u8907\u96d1\u306a\u7d50\u5408\u30af\u30a8\u30ea\n  scope :popular_with_comments, -&gt; {\n    joins(:comments)\n      .group('posts.id')\n      .select('posts.*, COUNT(comments.id) as comments_count')\n      .having('COUNT(comments.id) &gt; ?', 5)\n      .order('comments_count DESC')\n  }\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-27\">3. \u30ab\u30b9\u30bf\u30e0SQL\u306e\u6d3b\u7528<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class Order &lt; ApplicationRecord\n  # \u58f2\u4e0a\u96c6\u8a08\u306e\u305f\u3081\u306e\u8907\u96d1\u306a\u30af\u30a8\u30ea\n  def self.monthly_sales_report\n    find_by_sql(&lt;&lt;-SQL)\n      SELECT \n        DATE_TRUNC('month', created_at) as month,\n        COUNT(*) as total_orders,\n        SUM(total_amount) as revenue,\n        AVG(total_amount) as average_order_value\n      FROM orders\n      WHERE status = 'completed'\n      GROUP BY DATE_TRUNC('month', created_at)\n      ORDER BY month DESC\n    SQL\n  end\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-28\">\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u52b9\u679c\u7684\u306a\u7ba1\u7406\u65b9\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-29\">1. \u5b89\u5168\u306a\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u8a2d\u8a08<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class AddUserSettingsToUsers &lt; ActiveRecord::Migration[7.0]\n  def up\n    # \u65b0\u3057\u3044\u30ab\u30e9\u30e0\u306e\u8ffd\u52a0\n    add_column :users, :settings, :jsonb, null: false, default: {}\n\n    # \u65e2\u5b58\u30c7\u30fc\u30bf\u306e\u79fb\u884c\n    User.find_each do |user|\n      user.update_column(:settings, {\n        notification_preferences: user.read_attribute(:notification_preferences) || {},\n        theme: 'light',\n        language: 'ja'\n      })\n    end\n\n    # \u53e4\u3044\u30ab\u30e9\u30e0\u306e\u524a\u9664\n    remove_column :users, :notification_preferences\n  end\n\n  def down\n    add_column :users, :notification_preferences, :jsonb\n\n    User.find_each do |user|\n      user.update_column(:notification_preferences, user.settings['notification_preferences'])\n    end\n\n    remove_column :users, :settings\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-30\">2. \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u7ba1\u7406<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class OptimizeDatabaseIndexes &lt; ActiveRecord::Migration[7.0]\n  def change\n    # \u8907\u5408\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u8ffd\u52a0\n    add_index :orders, [:user_id, :created_at]\n\n    # \u30e6\u30cb\u30fc\u30af\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u8ffd\u52a0\n    add_index :users, :email, unique: true, where: \"deleted_at IS NULL\"\n\n    # \u90e8\u5206\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u8ffd\u52a0\n    add_index :posts, :published_at, where: \"status = 'published'\"\n\n    # \u4e0d\u8981\u306a\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u524a\u9664\n    remove_index :comments, :updated_at\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-31\">3. \u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u5236\u7d04\u306e\u7ba1\u7406<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class AddConstraintsToOrders &lt; ActiveRecord::Migration[7.0]\n  def change\n    # CHECK\u5236\u7d04\u306e\u8ffd\u52a0\n    add_check_constraint :orders, \"total_amount &gt;= 0\", name: \"check_positive_amount\"\n\n    # \u5916\u90e8\u30ad\u30fc\u5236\u7d04\u306e\u8ffd\u52a0\n    add_foreign_key :orders, :users, on_delete: :restrict\n\n    # NOT NULL\u5236\u7d04\u306e\u8ffd\u52a0\n    change_column_null :orders, :status, false\n\n    # \u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u306e\u8a2d\u5b9a\n    change_column_default :orders, :status, from: nil, to: 'pending'\n  end\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-32\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u8003\u616e\u3057\u305f\u30af\u30a8\u30ea\u306e\u66f8\u304d\u65b9<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-33\">1. N+1\u554f\u984c\u306e\u89e3\u6c7a<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># \u60aa\u3044\u4f8b\ndef index\n  @posts = Post.all\n  # N+1\u554f\u984c: \u5404\u6295\u7a3f\u306b\u5bfe\u3057\u3066\u30e6\u30fc\u30b6\u30fc\u3068\u30b3\u30e1\u30f3\u30c8\u306e\u30af\u30a8\u30ea\u304c\u5b9f\u884c\u3055\u308c\u308b\n  @posts.each do |post|\n    puts \"#{post.user.name}: #{post.comments.count} comments\"\n  end\nend\n\n# \u826f\u3044\u4f8b\ndef index\n  @posts = Post.includes(:user, :comments)\n  # \u5fc5\u8981\u306a\u30c7\u30fc\u30bf\u30921\u5ea6\u306b\u53d6\u5f97\n  @posts.each do |post|\n    puts \"#{post.user.name}: #{post.comments.size} comments\"\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-34\">2. \u30d0\u30c3\u30c1\u51e6\u7406\u306e\u6700\u9069\u5316<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class BatchProcessor\n  def self.process_large_dataset\n    # find_each\u3092\u4f7f\u7528\u3057\u3066\u5c11\u3057\u305a\u3064\u51e6\u7406\n    User.find_each(batch_size: 1000) do |user|\n      user.calculate_statistics\n    end\n  end\n\n  def self.bulk_update_records\n    # bulk_insert\u3092\u4f7f\u7528\u3057\u3066\u4e00\u62ec\u633f\u5165\n    users_data = generate_users_data(10000)\n    User.insert_all(users_data)\n\n    # bulk_update\u3092\u4f7f\u7528\u3057\u3066\u4e00\u62ec\u66f4\u65b0\n    updates = User.where(status: 'pending').select(:id).map do |user|\n      { id: user.id, status: 'active', updated_at: Time.current }\n    end\n    User.upsert_all(updates)\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-35\">3. \u30af\u30a8\u30ea\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u6d3b\u7528<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class CacheOptimizedQueries\n  def self.cached_popular_posts\n    Rails.cache.fetch('popular_posts', expires_in: 1.hour) do\n      Post.popular_with_comments.limit(10).to_a\n    end\n  end\n\n  def self.cached_user_statistics(user_id)\n    Rails.cache.fetch(\"user_stats\/#{user_id}\", expires_in: 30.minutes) do\n      User.find(user_id).calculate_statistics\n    end\n  end\nend<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30c6\u30af\u30cb\u30c3\u30af\u3092\u9069\u5207\u306b\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u52b9\u7387\u7684\u3067\u4fdd\u5b88\u6027\u306e\u9ad8\u3044\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u64cd\u4f5c\u3092\u5b9f\u73fe\u3067\u304d\u307e\u3059\u3002\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u610f\u8b58\u3057\u306a\u304c\u3089\u3001\u9069\u5207\u306a\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3068\u30ad\u30e3\u30c3\u30b7\u30e5\u6226\u7565\u3092\u63a1\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u5fdc\u7b54\u6027\u3092\u5411\u4e0a\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"i-36\">\u30c6\u30b9\u30c8\u99c6\u52d5\u958b\u767a\u306e\u5b9f\u8df5<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-37\">RSpec\u306b\u3088\u308b\u52b9\u7387\u7684\u306a\u30c6\u30b9\u30c8\u8a2d\u8a08<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-38\">1. \u30c6\u30b9\u30c8\u306e\u57fa\u672c\u69cb\u9020<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># spec\/models\/user_spec.rb\nrequire 'rails_helper'\n\nRSpec.describe User, type: :model do\n  # let\u3092\u4f7f\u7528\u3057\u305f\u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u306e\u5b9a\u7fa9\n  let(:user) { build(:user) }\n  let(:admin) { build(:user, :admin) }\n\n  # \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u3088\u308b\u30c6\u30b9\u30c8\u306e\u30b0\u30eb\u30fc\u30d7\u5316\n  context '\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3' do\n    it '\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u304c\u306a\u3044\u5834\u5408\u306f\u7121\u52b9' do\n      user.email = nil\n      expect(user).not_to be_valid\n    end\n\n    it '\u30d1\u30b9\u30ef\u30fc\u30c9\u304c\u77ed\u3059\u304e\u308b\u5834\u5408\u306f\u7121\u52b9' do\n      user.password = '123'\n      expect(user).not_to be_valid\n      expect(user.errors[:password]).to include('\u306f6\u6587\u5b57\u4ee5\u4e0a\u3067\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044')\n    end\n  end\n\n  # \u5171\u6709\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u4f7f\u7528\n  context '\u7ba1\u7406\u8005\u6a29\u9650' do\n    it '\u7ba1\u7406\u8005\u306f\u7279\u5225\u306a\u6a29\u9650\u3092\u6301\u3064' do\n      expect(admin).to be_admin\n      expect(admin.can_manage_users?).to be true\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-39\">2. \u30d5\u30a1\u30af\u30c8\u30ea\u306e\u52b9\u679c\u7684\u306a\u8a2d\u5b9a<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># spec\/factories\/users.rb\nFactoryBot.define do\n  factory :user do\n    sequence(:email) { |n| \"user#{n}@example.com\" }\n    password { 'password123' }\n    username { Faker::Internet.username }\n\n    # \u30c8\u30ec\u30a4\u30c8\u3092\u4f7f\u7528\u3057\u305f\u67d4\u8edf\u306a\u30c7\u30fc\u30bf\u4f5c\u6210\n    trait :admin do\n      admin { true }\n      role { 'administrator' }\n    end\n\n    trait :with_posts do\n      after(:create) do |user|\n        create_list(:post, 3, user: user)\n      end\n    end\n\n    # \u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u306e\u6d3b\u7528\n    after(:build) do |user|\n      user.build_profile if user.profile.nil?\n    end\n  end\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-40\">\u30c6\u30b9\u30c8\u30b1\u30fc\u30b9\u306e\u4f5c\u6210\u3068\u5b9f\u884c\u65b9\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-41\">1. \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u30c6\u30b9\u30c8<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># spec\/controllers\/posts_controller_spec.rb\nRSpec.describe PostsController, type: :controller do\n  let(:user) { create(:user) }\n  let(:post_item) { create(:post, user: user) }\n\n  describe 'GET #index' do\n    context '\u8a8d\u8a3c\u6e08\u307f\u30e6\u30fc\u30b6\u30fc' do\n      before { sign_in user }\n\n      it '\u6b63\u5e38\u306b\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u8fd4\u3059' do\n        get :index\n        expect(response).to have_http_status(:success)\n      end\n\n      it '\u3059\u3079\u3066\u306e\u6295\u7a3f\u3092\u53d6\u5f97\u3059\u308b' do\n        posts = create_list(:post, 3)\n        get :index\n        expect(assigns(:posts)).to match_array(posts)\n      end\n    end\n  end\n\n  describe 'POST #create' do\n    context '\u6709\u52b9\u306a\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u5834\u5408' do\n      it '\u65b0\u3057\u3044\u6295\u7a3f\u3092\u4f5c\u6210\u3059\u308b' do\n        sign_in user\n        post_params = attributes_for(:post)\n        expect {\n          post :create, params: { post: post_params }\n        }.to change(Post, :count).by(1)\n      end\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-42\">2. \u30b7\u30b9\u30c6\u30e0\u30c6\u30b9\u30c8<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># spec\/system\/user_registration_spec.rb\nRSpec.describe '\u30e6\u30fc\u30b6\u30fc\u767b\u9332', type: :system do\n  before do\n    driven_by(:rack_test)\n  end\n\n  scenario '\u30e6\u30fc\u30b6\u30fc\u304c\u65b0\u898f\u767b\u9332\u3059\u308b' do\n    visit new_user_registration_path\n\n    fill_in '\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9', with: 'test@example.com'\n    fill_in '\u30d1\u30b9\u30ef\u30fc\u30c9', with: 'password123'\n    fill_in '\u30d1\u30b9\u30ef\u30fc\u30c9\uff08\u78ba\u8a8d\uff09', with: 'password123'\n\n    expect {\n      click_button '\u767b\u9332'\n    }.to change(User, :count).by(1)\n\n    expect(page).to have_content('\u30a2\u30ab\u30a6\u30f3\u30c8\u767b\u9332\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f')\n  end\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-43\">\u30e2\u30c3\u30af\u3068\u30b9\u30bf\u30d6\u306e\u6d3b\u7528\u30c6\u30af\u30cb\u30c3\u30af<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-44\">1. \u30b5\u30fc\u30d3\u30b9\u306e\u30e2\u30c3\u30af\u5316<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># spec\/services\/payment_service_spec.rb\nRSpec.describe PaymentService do\n  let(:user) { create(:user) }\n  let(:order) { create(:order, user: user) }\n\n  describe '#process_payment' do\n    context '\u5916\u90e8\u6c7a\u6e08\u30b5\u30fc\u30d3\u30b9\u3068\u306e\u9023\u643a' do\n      it '\u652f\u6255\u3044\u304c\u6210\u529f\u3059\u308b\u5834\u5408' do\n        payment_client = instance_double('PaymentClient')\n        allow(payment_client).to receive(:charge).and_return(\n          success: true,\n          transaction_id: 'tx_123'\n        )\n\n        service = PaymentService.new(order, payment_client)\n        result = service.process_payment\n\n        expect(result).to be_successful\n        expect(order.reload.status).to eq('paid')\n      end\n\n      it '\u652f\u6255\u3044\u304c\u5931\u6557\u3059\u308b\u5834\u5408' do\n        payment_client = instance_double('PaymentClient')\n        allow(payment_client).to receive(:charge).and_raise(\n          PaymentError.new('\u30ab\u30fc\u30c9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f')\n        )\n\n        service = PaymentService.new(order, payment_client)\n        result = service.process_payment\n\n        expect(result).not_to be_successful\n        expect(order.reload.status).to eq('payment_failed')\n      end\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-45\">2. \u6642\u9593\u4f9d\u5b58\u306e\u30c6\u30b9\u30c8<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># spec\/models\/subscription_spec.rb\nRSpec.describe Subscription do\n  describe '#active?' do\n    let(:subscription) { create(:subscription) }\n\n    it '\u6709\u52b9\u671f\u9650\u5185\u306e\u5834\u5408\u306ftrue\u3092\u8fd4\u3059' do\n      travel_to Time.zone.local(2024, 1, 1, 12, 0, 0) do\n        subscription.expires_at = 1.month.from_now\n        expect(subscription).to be_active\n      end\n    end\n\n    it '\u6709\u52b9\u671f\u9650\u5207\u308c\u306e\u5834\u5408\u306ffalse\u3092\u8fd4\u3059' do\n      travel_to Time.zone.local(2024, 1, 1, 12, 0, 0) do\n        subscription.expires_at = 1.day.ago\n        expect(subscription).not_to be_active\n      end\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-46\">3. \u30e1\u30fc\u30eb\u9001\u4fe1\u306e\u30c6\u30b9\u30c8<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># spec\/mailers\/notification_mailer_spec.rb\nRSpec.describe NotificationMailer do\n  let(:user) { create(:user) }\n\n  describe '#welcome_email' do\n    subject(:mail) { described_class.welcome_email(user) }\n\n    it '\u6b63\u3057\u3044\u5b9b\u5148\u306b\u30e1\u30fc\u30eb\u304c\u9001\u4fe1\u3055\u308c\u308b' do\n      expect(mail.to).to eq([user.email])\n    end\n\n    it '\u6b63\u3057\u3044\u4ef6\u540d\u304c\u8a2d\u5b9a\u3055\u308c\u308b' do\n      expect(mail.subject).to eq('\u3088\u3046\u3053\u305d\uff01')\n    end\n\n    it '\u30e1\u30fc\u30eb\u672c\u6587\u306b\u30e6\u30fc\u30b6\u30fc\u540d\u304c\u542b\u307e\u308c\u308b' do\n      expect(mail.body.encoded).to include(user.username)\n    end\n  end\nend<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30c6\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u3092\u63a1\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u4fe1\u983c\u6027\u306e\u9ad8\u3044\u30b3\u30fc\u30c9\u30d9\u30fc\u30b9\u3092\u7dad\u6301\u3057\u3001\u30ea\u30b0\u30ec\u30c3\u30b7\u30e7\u30f3\u3092\u9632\u3050\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u307e\u305f\u3001\u30c6\u30b9\u30c8\u99c6\u52d5\u958b\u767a\u3092\u5b9f\u8df5\u3059\u308b\u3053\u3068\u3067\u3001\u8a2d\u8a08\u306e\u54c1\u8cea\u5411\u4e0a\u3068\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u6027\u306e\u5411\u4e0a\u3092\u56f3\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"i-47\">\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u306e\u5b9f\u88c5<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-48\">\u4e00\u822c\u7684\u306a\u8106\u5f31\u6027\u3078\u306e\u5bfe\u51e6\u65b9\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-49\">1. XSS\uff08\u30af\u30ed\u30b9\u30b5\u30a4\u30c8\u30b9\u30af\u30ea\u30d7\u30c6\u30a3\u30f3\u30b0\uff09\u5bfe\u7b56<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config\/initializers\/content_security_policy.rb\nRails.application.config.content_security_policy do |policy|\n  policy.default_src :self\n  policy.font_src    :self, :https, :data\n  policy.img_src     :self, :https, :data\n  policy.object_src  :none\n  policy.script_src  :self\n  policy.style_src   :self, :https\n  policy.frame_ancestors :none\n  policy.base_uri    :self\n  policy.form_action :self\nend\n\n# app\/helpers\/application_helper.rb\nmodule ApplicationHelper\n  def safe_user_content(content)\n    sanitize content, tags: %w[p b i u ul li ol], attributes: %w[class id]\n  end\nend\n\n# app\/views\/posts\/show.html.erb\n&lt;div class=\"post-content\"&gt;\n  &lt;%= safe_user_content(@post.content) %&gt;\n&lt;\/div&gt;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-50\">2. CSRF\uff08\u30af\u30ed\u30b9\u30b5\u30a4\u30c8\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a9\u30fc\u30b8\u30a7\u30ea\uff09\u5bfe\u7b56<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/controllers\/application_controller.rb\nclass ApplicationController &lt; ActionController::Base\n  protect_from_forgery with: :exception\n  before_action :verify_authenticity_token\n\n  # API\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u5834\u5408\u306fCSRF\u30c1\u30a7\u30c3\u30af\u3092\u30b9\u30ad\u30c3\u30d7\n  skip_before_action :verify_authenticity_token, if: :json_request?\n\n  private\n\n  def json_request?\n    request.format.json?\n  end\nend\n\n# app\/views\/forms\/_secure_form.html.erb\n&lt;%= form_with(model: @resource, local: true) do |f| %&gt;\n  &lt;%= csrf_meta_tags %&gt;\n  &lt;!-- \u30d5\u30a9\u30fc\u30e0\u306e\u5185\u5bb9 --&gt;\n&lt;% end %&gt;<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-51\">3. SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class User &lt; ApplicationRecord\n  # \u60aa\u3044\u4f8b\n  def self.search_unsafe(query)\n    where(\"name LIKE '%#{query}%'\") # SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u306e\u5371\u967a\u3042\u308a\n  end\n\n  # \u826f\u3044\u4f8b\n  def self.search_safe(query)\n    where(\"name LIKE ?\", \"%#{sanitize_sql_like(query)}%\")\n  end\n\n  # \u3055\u3089\u306b\u826f\u3044\u4f8b\uff1a\u30b9\u30b3\u30fc\u30d7\u3092\u4f7f\u7528\n  scope :search_by_name, -&gt;(query) {\n    where(\"name ILIKE :query\", query: \"%#{sanitize_sql_like(query)}%\")\n  }\nend\n\n# \u914d\u5217\u6761\u4ef6\u3092\u4f7f\u7528\u3057\u305f\u5b89\u5168\u306a\u30af\u30a8\u30ea\ndef find_users_by_status(statuses)\n  User.where(status: statuses)\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-52\">\u8a8d\u8a3c\u30fb\u8a8d\u53ef\u306e\u5b9f\u88c5\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-53\">1. Devise\u3092\u4f7f\u7528\u3057\u305f\u5805\u7262\u306a\u8a8d\u8a3c<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/models\/user.rb\nclass User &lt; ApplicationRecord\n  devise :database_authenticatable, :registerable,\n         :recoverable, :rememberable, :validatable,\n         :confirmable, :lockable, :timeoutable, :trackable,\n         :jwt_authenticatable, jwt_revocation_strategy: JwtDenylist\n\n  # \u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u8907\u96d1\u6027\u8981\u4ef6\n  validate :password_complexity\n\n  private\n\n  def password_complexity\n    return if password.blank?\n    unless password.match?(\/^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*#?&amp;])[A-Za-z\\d@$!%*#?&amp;]{8,}$\/)\n      errors.add :password, '\u306b\u306f\u6587\u5b57\u3001\u6570\u5b57\u3001\u7279\u6b8a\u6587\u5b57\u3092\u542b\u3081\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059'\n    end\n  end\nend\n\n# config\/initializers\/devise.rb\nDevise.setup do |config|\n  config.password_length = 8..128\n  config.unlock_strategy = :time\n  config.maximum_attempts = 5\n  config.unlock_in = 1.hour\n  config.timeout_in = 30.minutes\n  config.remember_for = 2.weeks\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-54\">2. Pundit\u3092\u4f7f\u7528\u3057\u305f\u7d30\u304b\u306a\u8a8d\u53ef\u5236\u5fa1<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/policies\/application_policy.rb\nclass ApplicationPolicy\n  attr_reader :user, :record\n\n  def initialize(user, record)\n    @user = user\n    @record = record\n  end\n\n  def index?\n    false\n  end\n\n  def show?\n    scope.where(id: record.id).exists?\n  end\n\n  private\n\n  def scope\n    Pundit.policy_scope!(user, record.class)\n  end\nend\n\n# app\/policies\/post_policy.rb\nclass PostPolicy &lt; ApplicationPolicy\n  def update?\n    user.admin? || record.user_id == user.id\n  end\n\n  def destroy?\n    user.admin? || record.user_id == user.id\n  end\n\n  class Scope &lt; Scope\n    def resolve\n      if user.admin?\n        scope.all\n      else\n        scope.where(published: true).or(scope.where(user_id: user.id))\n      end\n    end\n  end\nend\n\n# app\/controllers\/posts_controller.rb\nclass PostsController &lt; ApplicationController\n  before_action :authenticate_user!\n  after_action :verify_authorized, except: :index\n  after_action :verify_policy_scoped, only: :index\n\n  def index\n    @posts = policy_scope(Post)\n  end\n\n  def update\n    @post = Post.find(params[:id])\n    authorize @post\n    if @post.update(post_params)\n      redirect_to @post, notice: '\u66f4\u65b0\u3057\u307e\u3057\u305f'\n    else\n      render :edit\n    end\n  end\nend<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-55\">\u30bb\u30ad\u30e5\u30a2\u306aAPI\u958b\u767a\u306e\u624b\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-56\">1. JWT\u3092\u4f7f\u7528\u3057\u305f\u8a8d\u8a3c<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># app\/controllers\/api\/v1\/base_controller.rb\nmodule Api\n  module V1\n    class BaseController &lt; ApplicationController\n      include JWTAuthentication\n\n      before_action :authenticate_api_request!\n\n      private\n\n      def authenticate_api_request!\n        token = extract_token_from_header\n        payload = decode_jwt_token(token)\n        @current_user = User.find(payload['sub'])\n      rescue JWT::DecodeError, ActiveRecord::RecordNotFound\n        render json: { error: '\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f' }, status: :unauthorized\n      end\n\n      def extract_token_from_header\n        header = request.headers['Authorization']\n        header&amp;.split(' ')&amp;.last\n      end\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-57\">2. \u30ec\u30fc\u30c8\u5236\u9650\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config\/initializers\/rack_attack.rb\nclass Rack::Attack\n  # IP\u30d9\u30fc\u30b9\u306e\u5236\u9650\n  throttle('req\/ip', limit: 300, period: 5.minutes) do |req|\n    req.ip unless req.path.start_with?('\/assets')\n  end\n\n  # \u30e6\u30fc\u30b6\u30fc\u30d9\u30fc\u30b9\u306e\u5236\u9650\n  throttle('api\/ip', limit: 100, period: 1.minute) do |req|\n    if req.path.start_with?('\/api\/')\n      req.ip\n    end\n  end\n\n  # \u30ed\u30b0\u30a4\u30f3\u8a66\u884c\u306e\u5236\u9650\n  throttle('login\/email', limit: 5, period: 20.minutes) do |req|\n    if req.path == '\/login' &amp;&amp; req.post?\n      req.params['email'].to_s.downcase\n    end\n  end\nend\n\n# \u5236\u9650\u8d85\u904e\u6642\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u8a2d\u5b9a\nRack::Attack.throttled_response = lambda do |env|\n  now = Time.now\n  match_data = env['rack.attack.match_data']\n  headers = {\n    'Content-Type' =&gt; 'application\/json',\n    'Retry-After' =&gt; (match_data[:period] - (now.to_i % match_data[:period])).to_s\n  }\n\n  [429, headers, [{ error: '\u30ea\u30af\u30a8\u30b9\u30c8\u5236\u9650\u3092\u8d85\u904e\u3057\u307e\u3057\u305f' }.to_json]]\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-58\">3. \u30bb\u30ad\u30e5\u30a2\u306a\u30d8\u30c3\u30c0\u30fc\u306e\u8a2d\u5b9a<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config\/initializers\/secure_headers.rb\nSecureHeaders::Configuration.default do |config|\n  config.x_frame_options = \"DENY\"\n  config.x_content_type_options = \"nosniff\"\n  config.x_xss_protection = \"1; mode=block\"\n  config.x_download_options = \"noopen\"\n  config.x_permitted_cross_domain_policies = \"none\"\n  config.referrer_policy = %w(strict-origin-when-cross-origin)\n\n  config.hsts = {\n    max_age: 2.years.to_i,\n    include_subdomains: true,\n    preload: true\n  }\nend<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u3092\u5b9f\u88c5\u3059\u308b\u3053\u3068\u3067\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u69d8\u3005\u306a\u8106\u5f31\u6027\u304b\u3089\u4fdd\u8b77\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u5b9a\u671f\u7684\u306a\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u76e3\u67fb\u3068\u66f4\u65b0\u3092\u884c\u3044\u3001\u65b0\u3057\u3044\u8106\u5f31\u6027\u306b\u5bfe\u3057\u3066\u3082\u9069\u5207\u306b\u5bfe\u5fdc\u3059\u308b\u3053\u3068\u304c\u91cd\u8981\u3067\u3059\u3002<\/p>\n\n\n\n<h1 class=\"wp-block-heading\" id=\"i-59\">\u30c7\u30d7\u30ed\u30a4\u30e1\u30f3\u30c8\u3068\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9<\/h1>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-60\">\u672c\u756a\u74b0\u5883\u3078\u306e\u30c7\u30d7\u30ed\u30a4\u624b\u9806<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-61\">1. \u30c7\u30d7\u30ed\u30a4\u6e96\u5099<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config\/environments\/production.rb\nRails.application.configure do\n  # \u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u8a2d\u5b9a\n  config.cache_classes = true\n  config.eager_load = true\n  config.cache_store = :redis_cache_store, {\n    url: ENV['REDIS_URL'],\n    pool_size: Integer(ENV.fetch('RAILS_MAX_THREADS', 5))\n  }\n\n  # \u30a2\u30bb\u30c3\u30c8\u306e\u8a2d\u5b9a\n  config.assets.js_compressor = :terser\n  config.assets.css_compressor = :sass\n  config.assets.compile = false\n\n  # \u30ed\u30b0\u306e\u8a2d\u5b9a\n  config.log_level = :info\n  config.log_tags = [:request_id]\n\n  # \u30e1\u30fc\u30eb\u914d\u4fe1\u306e\u8a2d\u5b9a\n  config.action_mailer.perform_caching = false\n  config.action_mailer.delivery_method = :smtp\n  config.action_mailer.smtp_settings = {\n    address: ENV['SMTP_SERVER'],\n    port: ENV['SMTP_PORT'],\n    user_name: ENV['SMTP_USERNAME'],\n    password: ENV['SMTP_PASSWORD'],\n    authentication: 'plain',\n    enable_starttls_auto: true\n  }\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-62\">2. Capfile\u306b\u3088\u308b\u30c7\u30d7\u30ed\u30a4\u8a2d\u5b9a<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Capfile\nrequire 'capistrano\/setup'\nrequire 'capistrano\/deploy'\nrequire 'capistrano\/rbenv'\nrequire 'capistrano\/bundler'\nrequire 'capistrano\/rails\/assets'\nrequire 'capistrano\/rails\/migrations'\nrequire 'capistrano\/puma'\n\n# config\/deploy.rb\nset :application, 'myapp'\nset :repo_url, 'git@github.com:username\/myapp.git'\nset :deploy_to, '\/var\/www\/myapp'\nset :linked_files, %w{config\/database.yml config\/master.key}\nset :linked_dirs, %w{log tmp\/pids tmp\/cache tmp\/sockets vendor\/bundle}\n\nnamespace :deploy do\n  desc 'Restart application'\n  task :restart do\n    on roles(:app), in: :sequence, wait: 5 do\n      execute :touch, release_path.join('tmp\/restart.txt')\n    end\n  end\n\n  after :publishing, :restart\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-63\">3. Docker\u3092\u4f7f\u7528\u3057\u305f\u30c7\u30d7\u30ed\u30a4<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Dockerfile\nFROM ruby:3.2.2\nRUN apt-get update -qq &amp;&amp; apt-get install -y nodejs postgresql-client\nWORKDIR \/myapp\nCOPY Gemfile \/myapp\/Gemfile\nCOPY Gemfile.lock \/myapp\/Gemfile.lock\nRUN bundle install\nCOPY . \/myapp\n\n# docker-compose.yml\nversion: '3'\nservices:\n  db:\n    image: postgres:13\n    volumes:\n      - postgres_data:\/var\/lib\/postgresql\/data\n    environment:\n      POSTGRES_PASSWORD: password\n\n  web:\n    build: .\n    command: bash -c \"rm -f tmp\/pids\/server.pid &amp;&amp; bundle exec rails s -p 3000 -b '0.0.0.0'\"\n    volumes:\n      - .:\/myapp\n    ports:\n      - \"3000:3000\"\n    depends_on:\n      - db\n    environment:\n      DATABASE_URL: postgres:\/\/postgres:password@db:5432\/myapp_production\n\nvolumes:\n  postgres_data:<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-64\">\u7d99\u7d9a\u7684\u30a4\u30f3\u30c6\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u69cb\u7bc9\u65b9\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-65\">1. GitHub Actions\u306e\u8a2d\u5b9a<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># .github\/workflows\/ci.yml\nname: CI\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    services:\n      postgres:\n        image: postgres:13\n        env:\n          POSTGRES_PASSWORD: postgres\n        ports: ['5432:5432']\n        options: &gt;-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n\n    steps:\n    - uses: actions\/checkout@v3\n\n    - name: Set up Ruby\n      uses: ruby\/setup-ruby@v1\n      with:\n        ruby-version: 3.2.2\n        bundler-cache: true\n\n    - name: Install dependencies\n      run: |\n        bundle install\n        yarn install\n\n    - name: Setup database\n      env:\n        RAILS_ENV: test\n        POSTGRES_HOST: localhost\n        POSTGRES_PORT: 5432\n      run: |\n        bundle exec rails db:create\n        bundle exec rails db:schema:load\n\n    - name: Run tests\n      run: bundle exec rspec\n\n    - name: Run security checks\n      run: |\n        bundle exec brakeman\n        bundle exec bundle-audit check --update<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-66\">\u52b9\u7387\u7684\u306a\u30c7\u30d0\u30c3\u30b0\u3068\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-67\">1. \u30ed\u30b0\u89e3\u6790\u3068\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config\/initializers\/lograge.rb\nRails.application.configure do\n  config.lograge.enabled = true\n  config.lograge.custom_options = lambda do |event|\n    {\n      params: event.payload[:params].except(*%w(controller action format id)),\n      time: Time.current,\n      user_id: event.payload[:user_id],\n      request_id: event.payload[:request_id]\n    }\n  end\nend\n\n# app\/controllers\/application_controller.rb\nclass ApplicationController &lt; ActionController::Base\n  include LoggingConcern\n\n  before_action :set_request_details\n\n  private\n\n  def set_request_details\n    RequestStore.store[:request_id] = request.uuid\n    RequestStore.store[:user_id] = current_user&amp;.id\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-68\">2. \u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0\u3068\u30ec\u30dd\u30fc\u30c6\u30a3\u30f3\u30b0<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config\/initializers\/error_reporting.rb\nSentry.init do |config|\n  config.dsn = ENV['SENTRY_DSN']\n  config.breadcrumbs_logger = [:active_support_logger, :http_logger]\n  config.traces_sample_rate = 0.1\nend\n\n# app\/controllers\/application_controller.rb\nclass ApplicationController &lt; ActionController::Base\n  rescue_from StandardError do |exception|\n    Sentry.capture_exception(exception)\n    respond_to do |format|\n      format.html { render 'errors\/internal_server_error', status: :internal_server_error }\n      format.json { render json: { error: '\u5185\u90e8\u30b5\u30fc\u30d0\u30fc\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f' }, status: :internal_server_error }\n    end\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-69\">3. \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u76e3\u8996<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># config\/initializers\/scout_apm.rb\nScoutApm.config do |config|\n  config.name = \"MyApp\"\n  config.monitor = true\nend\n\n# \u30ab\u30b9\u30bf\u30e0\u30e1\u30c8\u30ea\u30af\u30b9\u306e\u8ffd\u52a0\nclass ApplicationController &lt; ActionController::Base\n  before_action :track_request_metrics\n\n  private\n\n  def track_request_metrics\n    ScoutApm::Context.add_tag(:user_id, current_user&amp;.id)\n    ScoutApm::Context.add_tag(:request_source, request.headers['X-Request-Source'])\n  end\nend<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-70\">4. \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u30bf\u30b9\u30af\u306e\u81ea\u52d5\u5316<\/h3>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># lib\/tasks\/maintenance.rake\nnamespace :maintenance do\n  desc \"\u53e4\u3044\u30bb\u30c3\u30b7\u30e7\u30f3\u30c7\u30fc\u30bf\u306e\u524a\u9664\"\n  task cleanup_sessions: :environment do\n    ActiveRecord::SessionStore::Session.where('updated_at &lt; ?', 2.weeks.ago).delete_all\n  end\n\n  desc \"\u4e00\u6642\u30d5\u30a1\u30a4\u30eb\u306e\u524a\u9664\"\n  task cleanup_temp_files: :environment do\n    TempFile.where('created_at &lt; ?', 1.day.ago).find_each do |file|\n      file.delete_from_storage\n      file.destroy\n    end\n  end\n\n  desc \"\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u306e\u4f5c\u6210\"\n  task create_backup: :environment do\n    timestamp = Time.current.strftime('%Y%m%d_%H%M%S')\n    system \"pg_dump -Fc #{Rails.configuration.database_configuration[Rails.env]['database']} &gt; backup_#{timestamp}.dump\"\n    system \"aws s3 cp backup_#{timestamp}.dump s3:\/\/myapp-backups\/\"\n  end\nend<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u8a2d\u5b9a\u3068\u30c4\u30fc\u30eb\u3092\u9069\u5207\u306b\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u5b89\u5b9a\u3057\u305f\u672c\u756a\u74b0\u5883\u306e\u904b\u7528\u3068\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002\u5b9a\u671f\u7684\u306a\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u3068\u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u3092\u884c\u3044\u3001\u554f\u984c\u306e\u65e9\u671f\u767a\u898b\u3068\u89e3\u6c7a\u3092\u5fc3\u304c\u3051\u308b\u3053\u3068\u304c\u91cd\u8981\u3067\u3059\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ruby on Rails\u306e\u57fa\u790e\u77e5\u8b58 Warning: Undefined array key &#8220;is_admin&#8221; in \/home\/xs392991\/dexall.co.jp\/public_html\/articles &#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":{"0":"post-1404","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-ruby","7":"nothumb"},"_links":{"self":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/1404","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1404"}],"version-history":[{"count":1,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/1404\/revisions"}],"predecessor-version":[{"id":1405,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/1404\/revisions\/1405"}],"wp:attachment":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1404"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1404"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1404"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}