<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Hideaki Ishii</title>
    <description>The latest articles on Forem by Hideaki Ishii (@danimal141).</description>
    <link>https://forem.com/danimal141</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178066%2F69a89743-d5cb-4256-a49b-de0fea9d87da.png</url>
      <title>Forem: Hideaki Ishii</title>
      <link>https://forem.com/danimal141</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/danimal141"/>
    <language>en</language>
    <item>
      <title>Create a sample app with TypeScript, React, typeorm, type-graphql. graphql-code-generator while reading "Learning GraphQL"</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sun, 24 Jan 2021 04:59:11 +0000</pubDate>
      <link>https://forem.com/danimal141/create-a-sample-app-with-typescript-react-typeorm-type-graphql-graphql-code-generator-while-reading-learning-graphql-2mcc</link>
      <guid>https://forem.com/danimal141/create-a-sample-app-with-typescript-react-typeorm-type-graphql-graphql-code-generator-while-reading-learning-graphql-2mcc</guid>
      <description>&lt;p&gt;Recently, I was reading a book &lt;a href="https://www.oreilly.com/library/view/learning-graphql/9781492030706/"&gt;Learning GraphQL&lt;/a&gt; to learn GraphQL.&lt;br&gt;
To understand it deeply, I tried to create a sample app: &lt;a href="https://github.com/danimal141/learning-graphql-ts"&gt;https://github.com/danimal141/learning-graphql-ts&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not interesting to just copy a sample app written in the book, so I used TypeScript, &lt;code&gt;typeorm&lt;/code&gt;, &lt;code&gt;type-graphql&lt;/code&gt;, &lt;code&gt;graphql-code-generator&lt;/code&gt;.&lt;br&gt;
I'm happy if this post is helpful for someone who tries to create the same application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The book uses JavaScript but I used TypeScript.

&lt;ul&gt;
&lt;li&gt;GraphQL itself has a type system, so I think TypeScript and GraphQL are compatible.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Adopted a Monorepo directory structure.

&lt;ul&gt;
&lt;li&gt;Used &lt;a href="https://classic.yarnpkg.com/blog/2017/08/02/introducing-workspaces/"&gt;yarn workspace&lt;/a&gt; to put all packages together.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Used &lt;a href="https://github.com/mysticatea/npm-run-all"&gt;npm-run-all&lt;/a&gt; to enable to run commands for the front-end and back-end at once.&lt;/li&gt;
&lt;li&gt;Used &lt;a href="https://github.com/okonet/lint-staged"&gt;lint-staged&lt;/a&gt; and &lt;a href="https://github.com/typicode/husky"&gt;husky&lt;/a&gt; to run Prettier when committing.&lt;/li&gt;
&lt;li&gt;Add ESLint etc.&lt;/li&gt;
&lt;li&gt;Sorry for skipping tests...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  back-end
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Used &lt;a href="https://github.com/typeorm/typeorm"&gt;typeorm&lt;/a&gt; and &lt;a href="https://github.com/MichalLytek/type-graphql"&gt;type-graphql&lt;/a&gt; to define the GraphQL schema and DB schema conveniently.

&lt;ul&gt;
&lt;li&gt;type-graphql automatically generates the schema file :)&lt;/li&gt;
&lt;li&gt;It might be better o try &lt;a href="https://github.com/nestjs/nest"&gt;Nest.js&lt;/a&gt;...?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  front-end
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Used &lt;a href="https://github.com/facebook/create-react-app"&gt;create-react-app&lt;/a&gt; to create a TypeScript based project.

&lt;ul&gt;
&lt;li&gt;Created only the user list view and login feature.&lt;/li&gt;
&lt;li&gt;The React way in the book seemed a bit old so I used React hooks actively.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Used &lt;a href="https://github.com/dotansimha/graphql-code-generator"&gt;graphql-code-generator&lt;/a&gt; to generate the types for TypeScript from the GraphQL schema that the back-end generated.&lt;/li&gt;
&lt;li&gt;Child components defines only GraphQL fragments and Root component should construct the whole query as much as possible (Fragment colocation).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/danimal141/learning-graphql-ts/blob/main/client/src/components/AuthorizedUser/index.tsx"&gt;Login feature&lt;/a&gt; was a bit hard for me because it's my first time to use Mutation...

&lt;ul&gt;
&lt;li&gt;The book uses &lt;code&gt;Mutation&lt;/code&gt; component、but I used React hooks instead.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GraphQL is awesome.&lt;/li&gt;
&lt;li&gt;TypeScript and GraphQL are compatible.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;typeorm&lt;/code&gt; seems good for back-end developments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/library/view/learning-graphql/9781492030706/"&gt;https://www.oreilly.com/library/view/learning-graphql/9781492030706/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://classic.yarnpkg.com/blog/2017/08/02/introducing-workspaces/"&gt;https://classic.yarnpkg.com/blog/2017/08/02/introducing-workspaces/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mysticatea/npm-run-all"&gt;https://github.com/mysticatea/npm-run-all&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/okonet/lint-staged"&gt;https://github.com/okonet/lint-staged&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/typicode/husky"&gt;https://github.com/typicode/husky&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/typeorm/typeorm"&gt;https://github.com/typeorm/typeorm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/MichalLytek/type-graphql"&gt;https://github.com/MichalLytek/type-graphql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nestjs/nest"&gt;https://github.com/nestjs/nest&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/facebook/create-react-app"&gt;https://github.com/facebook/create-react-app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dotansimha/graphql-code-generator"&gt;https://github.com/dotansimha/graphql-code-generator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>react</category>
      <category>graphql</category>
    </item>
    <item>
      <title>What is a good code review?</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sat, 14 Nov 2020 13:46:43 +0000</pubDate>
      <link>https://forem.com/danimal141/what-is-a-good-code-review-2cd1</link>
      <guid>https://forem.com/danimal141/what-is-a-good-code-review-2cd1</guid>
      <description>&lt;p&gt;I've put together a list of points like what is important I think in code review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Purpose of Code Review
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure the quality of your product

&lt;ul&gt;
&lt;li&gt;People basically make mistakes&lt;/li&gt;
&lt;li&gt;Two heads are better than one&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;To share knowledge with the team

&lt;ul&gt;
&lt;li&gt;Sharing knowledge of the code with the team at all times avoids the problem of personalization, e.g., "Only A-san knows this feature, I don't know...".&lt;/li&gt;
&lt;li&gt;It's a great opportunity where you can read other member's code and ask questions if any.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;To share responsibility within the team

&lt;ul&gt;
&lt;li&gt;When something goes wrong, only the person who wrote the relevant code should never be blamed.&lt;/li&gt;
&lt;li&gt;It's the responsibility of the team not to notice the problem at the time of review (or until the code is deployed), so we should fix problems as a team.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reviewer edition
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Points to keep in mind when reviewing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;What should you review in PR?&lt;/li&gt;
&lt;li&gt;Does the code meet the Acceptance Criteria for the relevant Issue?

&lt;ul&gt;
&lt;li&gt;It's necessary for reviewers to check the behavior as well in your local if the code affects the UI.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Is the code design OK?

&lt;ul&gt;
&lt;li&gt;Is it extensible?&lt;/li&gt;
&lt;li&gt;Can you update the code easily when some specification changes?&lt;/li&gt;
&lt;li&gt;If it's a disposable part, you would be able to refactor it later, but if it's a core part of the product (such as DB design), it's better to review the design carefully.&lt;/li&gt;
&lt;li&gt;Are responsibilities for classes and methods properly separated? (Single Responsibility Principle)&lt;/li&gt;
&lt;li&gt;Is the implementation easy to test?

&lt;ul&gt;
&lt;li&gt;Hard to write tests -&amp;gt; In many cases, the responsibilities of the class or method are wrong/bad.&lt;/li&gt;
&lt;li&gt;The code may include too many dependencies or may try to do too many things.&lt;/li&gt;
&lt;li&gt;If you see a method name like &lt;code&gt;a_and_b&lt;/code&gt;, it obviously means to do more than one thing, and it can be often isolated the methods.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Is dependency OK?&lt;/li&gt;
&lt;li&gt;Model depends on View, etc.&lt;/li&gt;
&lt;li&gt;Is error handling well?&lt;/li&gt;
&lt;li&gt;Doesn't the code return a server error when it's clearly a client error in the API.&lt;/li&gt;
&lt;li&gt;Can you understand/solve the problem from the error information? (traceable?)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Are the tests enough?&lt;/li&gt;
&lt;li&gt;Are there any bugs?&lt;/li&gt;
&lt;li&gt;Are existent features still working well? (Some feature is not broken?)&lt;/li&gt;
&lt;li&gt;Does deploy the code cause downtime?

&lt;ul&gt;
&lt;li&gt;If yes, is the deployment flow proposed properly?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Are there any security risks?&lt;/li&gt;
&lt;li&gt;Does the coding style follow the rules within the team?

&lt;ul&gt;
&lt;li&gt;Basically, it's better to automate it like "check by Lint -&amp;gt; fail in CI if something is needed to fix it" instead of discussing it in a review.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mindset
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You should assume that you are going to maintain the code later on.

&lt;ul&gt;
&lt;li&gt;If you think, "This is going to be tough to maintain," you should do your best to improve the quality for your future self by review.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Let's review it in terms of "how would you design it if you were to implement it?".

&lt;ul&gt;
&lt;li&gt;Comparing your design to theirs will help you enhance your design skills and would lead to more constructive discussions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If you feel some implementation isn't good, you should point out the code, not the person.

&lt;ul&gt;
&lt;li&gt;When pointing something out, let's always give reasons why you think it's not good.&lt;/li&gt;
&lt;li&gt;If it turns out your point is incorrect, you should apologize honestly, and please appreciate the reviewee for discussing it.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Let's ask questions about the parts you don't understand.

&lt;ul&gt;
&lt;li&gt;The reviewee can notice mistakes from the questions, and even if there are no problems, both can learn, and the reviewee can feel confident in their implementation.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Let's answer questions from the reviewee sincerely.

&lt;ul&gt;
&lt;li&gt;Your review sometimes may confuse the reviewee due to the knowledge gap, in that case providing sample code or sharing links to articles may be helpful.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;If the discussion is going to be difficult on a PR (e.g. there are so many comments in a PR and discussion is still going on), it might be better to suggest having a meeting or pair programming or something like that.&lt;/li&gt;
&lt;li&gt;It's better not to push your preferences too far.

&lt;ul&gt;
&lt;li&gt;If it's a matter of preference, you can basically respect the reviewee's approach.&lt;/li&gt;
&lt;li&gt;If you wanna share your preference, it's good to use tags like FYI, IMO, nits, etc to inform the point is not serious.&lt;/li&gt;
&lt;li&gt;If it's about coding style, it might be a good idea to suggest if the team can reconsider the lint rules and coding conventions.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Let's actively praise what you think is good

&lt;ul&gt;
&lt;li&gt;Reviews are often mainly about pointing out things, so if you think it's good and you learn something through the review, let's praise the reviewee's code and design.&lt;/li&gt;
&lt;li&gt;This kind of communication often makes for a better team atmosphere (I guess).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reviewee edition
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Points to keep in mind when being reviewed.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Do you specify what you want people to review in your PR?

&lt;ul&gt;
&lt;li&gt;Acceptance criteria&lt;/li&gt;
&lt;li&gt;Is the PR scope clear?&lt;/li&gt;
&lt;li&gt;What has been implemented in the PR?&lt;/li&gt;
&lt;li&gt;What is not implemented in the PR?

&lt;ul&gt;
&lt;li&gt;If you are leaving a TODO, do you create a separate issue for it?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Does the code meet the Acceptance Criteria for the relevant Issue?

&lt;ul&gt;
&lt;li&gt;Always self-review before requesting a review, so that the reviewer doesn't have to review so many points.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Is the volume of the PR appropriate?

&lt;ul&gt;
&lt;li&gt;Huge PRs make it difficult for reviewers to notice problems when reviewing, so let's avoid them as much as possible.&lt;/li&gt;
&lt;li&gt;Can we split up the PR and request a review?&lt;/li&gt;
&lt;li&gt;For example, if the PR is large and includes a library update, it looks like it can be split into a PR for the library update and a PR to resolve the actual issue.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Is the implementation simple?

&lt;ul&gt;
&lt;li&gt;Is the code you wrote still understandable to anyone, including you, a few months later?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Did you leave supplementary comments in the code or PR if some implementation may not be able to understand your intentions in the code alone?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Mindset
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You should be able to answer any questions about your implementation.

&lt;ul&gt;
&lt;li&gt;If you refer to something, share the reference link as well.&lt;/li&gt;
&lt;li&gt;Official documentation is better than someone's blog post.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Let's ask questions if you don't understand a reviewer's point.

&lt;ul&gt;
&lt;li&gt;let's follow the reviewer's points after you are convinced them (don't follow without understanding/considering)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;The reviewer's point of view is beneficial to you.

&lt;ul&gt;
&lt;li&gt;Pointing things out in a review is a great opportunity to learn how others think better, and you may notice your mistakes and it would lead to your growth.&lt;/li&gt;
&lt;li&gt;You may sometimes feel disappointed when you are pointed out, let's be strong and overcome :)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>codequality</category>
      <category>codenewbie</category>
      <category>codereview</category>
    </item>
    <item>
      <title>The difference between Mocks, Stubs, and Spies</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sun, 06 Sep 2020 03:23:03 +0000</pubDate>
      <link>https://forem.com/danimal141/the-difference-between-mocks-stubs-and-spies-11k9</link>
      <guid>https://forem.com/danimal141/the-difference-between-mocks-stubs-and-spies-11k9</guid>
      <description>&lt;p&gt;This post describes the difference between Mocks, Stubs, and Spies, and I use RSpec to show examples.&lt;/p&gt;

&lt;p&gt;I hope this helps you write excellent tests!&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://martinfowler.com/articles/mocksArentStubs.html"&gt;this great article&lt;/a&gt;, Mr. Martin Fowler says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.&lt;/p&gt;

&lt;p&gt;Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.&lt;/p&gt;

&lt;p&gt;Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  See the difference with RSpec
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Stubs
&lt;/h3&gt;

&lt;p&gt;For example, if some method depends on a third-party API, it's not good to request it whenever testing.&lt;br&gt;
In that case, stubs are very useful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeClient&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;request&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;some_lib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;
    &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_lib&lt;/span&gt;
    &lt;span class="vi"&gt;@some_lib&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;SomeLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'SomeClient#request'&lt;/span&gt;
  &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:some_lib&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_lib&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_boby&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;SomeClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:some_lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;instance_double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SomeLib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:expected_body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:expected_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;expected_body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="n"&gt;expected_json&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can avoid calling the API actually by stubs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mocks
&lt;/h3&gt;

&lt;p&gt;In the above stub example, if the client actually calls the API many times, it's completely unexpected.&lt;/p&gt;

&lt;p&gt;If we want to ensure whether the &lt;code&gt;some_lib&lt;/code&gt; method is invoked expectedly, using mocks is more suitable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'SomeClient#request'&lt;/span&gt;
  &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:some_lib&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;SomeClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:some_lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;instance_double&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SomeLib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:expected_body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:expected_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;expected_body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_lib&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_boby&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt; &lt;span class="c1"&gt;# Ensure it's really called expectedly.&lt;/span&gt;
    &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="n"&gt;expected_json&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;SomeLib#request&lt;/code&gt; is called unexpectedly (wrong args, called many times, etc.), the test will fail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spies
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;rspec-mocks&lt;/code&gt;, though it's a bit difficult to clarify the difference between mocks and spies...&lt;/p&gt;

&lt;p&gt;RSpec documentation says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Message expectations put an example's expectation at the start, before you've invoked the code-under-test. Many developers prefer using an arrange-act-assert (or given-when-then) pattern for structuring tests. Spies are an alternate type of test double that support this pattern by allowing you to expect that a message has been received after the fact, using have_received.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above example would become with spies like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'SomeClient#request'&lt;/span&gt;
  &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:some_lib&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;SomeClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:some_lib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;instance_spy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SomeLib&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# It's OK to use `instance_double` instead, I describe the difference afterward.&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:expected_body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:expected_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt; &lt;span class="n"&gt;expected_body&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="n"&gt;expected_json&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_lib&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;have_received&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:request&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_args&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;and_return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expected_boby&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might be more intuitive.&lt;/p&gt;

&lt;p&gt;After &lt;code&gt;subject&lt;/code&gt; is called, the test checks whether &lt;code&gt;SomeLib#request&lt;/code&gt; is really called expectedly.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;instance_spy(SomeLib)&lt;/code&gt; is similar to &lt;code&gt;instance_double(SomeLib)&lt;/code&gt;. The difference is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;instance_double&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Can stub methods.&lt;/li&gt;
&lt;li&gt;If you try to stub the undefined method, it would raise an error.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;instance_spy&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Mix stubs and real objects.&lt;/li&gt;
&lt;li&gt;If some real method is not stubbed, the real one would be called.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Let's clarify the difference and write excellent tests!&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/articles/mocksArentStubs.html"&gt;https://martinfowler.com/articles/mocksArentStubs.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/articles/mocksArentStubs.html"&gt;https://martinfowler.com/articles/mocksArentStubs.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>ruby</category>
      <category>rspec</category>
    </item>
    <item>
      <title>How to connect your DB with an SSH Tunnel and Docker</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sat, 05 Sep 2020 06:48:08 +0000</pubDate>
      <link>https://forem.com/danimal141/how-to-connect-your-db-with-an-ssh-tunnel-and-docker-5dp1</link>
      <guid>https://forem.com/danimal141/how-to-connect-your-db-with-an-ssh-tunnel-and-docker-5dp1</guid>
      <description>&lt;p&gt;When using a database like PostgreSQL, we usually use a managed database like Amazon RDS nowadays.&lt;/p&gt;

&lt;p&gt;Then we would configure to allow only some servers to connect to the database (e.g. only EC2 servers can connect to a database on RDS).&lt;/p&gt;

&lt;p&gt;But sometimes, we want to connect to such a database and check something from our local. In that case, we can use an SSH tunnel way.&lt;/p&gt;

&lt;p&gt;This post describes how to do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker image
&lt;/h2&gt;

&lt;p&gt;To connect to your database, you have to execute a command like &lt;code&gt;psql&lt;/code&gt;, &lt;code&gt;mysql&lt;/code&gt;, or something like that.&lt;br&gt;
So let's prepare a Docker image which is compatible with your actual database.&lt;/p&gt;

&lt;p&gt;In this post, I plan to use PostgreSQL as an example, but there is no PostgreSQL specific information. Please select your favorite one.&lt;/p&gt;
&lt;h2&gt;
  
  
  SSH tunnel
&lt;/h2&gt;

&lt;p&gt;Let's try to create an SSH tunnel next!&lt;/p&gt;

&lt;p&gt;The actual command would be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ssh &lt;span class="nt"&gt;-L&lt;/span&gt; 15432:db.some-service.jp:5432 web.some-service.jp &lt;span class="nt"&gt;-N&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To do that, you have to be able to ssh &lt;code&gt;web.some-service.jp&lt;/code&gt;, if your SSH tunneling failed, please try &lt;code&gt;ssh -i {your_ssh_key} {your_ssh_user}@web.some-service.jp&lt;/code&gt; or make sure your ssh config is correct.&lt;/p&gt;

&lt;p&gt;The above command means forwarding your local's 15432 port to &lt;code&gt;db.some-service.jp&lt;/code&gt;'s 5432 port.&lt;/p&gt;

&lt;p&gt;By specifying &lt;code&gt;-N&lt;/code&gt; option, the command does not execute a remote command. This is useful for just forwarding ports.&lt;/p&gt;

&lt;p&gt;Don't close this command and let's try to actually connect to your database in the next step!&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect to your database
&lt;/h2&gt;

&lt;p&gt;Please open a new tab and let's try to connect to your database.&lt;/p&gt;

&lt;p&gt;The actual command would be like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; postgres:11.9 psql &lt;span class="nt"&gt;-h&lt;/span&gt; host.docker.internal &lt;span class="nt"&gt;-p&lt;/span&gt; 15432 &lt;span class="nt"&gt;-U&lt;/span&gt; db-user &lt;span class="nt"&gt;-W&lt;/span&gt; db_name

&lt;span class="c"&gt;# Enter your db password&lt;/span&gt;
Password:
&lt;span class="nv"&gt;db_name&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; SELECT &lt;span class="k"&gt;*&lt;/span&gt; from &lt;span class="nb"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can connect to the special DNS name &lt;code&gt;host.docker.internal&lt;/code&gt; which resolves to the internal IP address used by the host.&lt;/p&gt;

&lt;p&gt;And then by specifying &lt;code&gt;15432&lt;/code&gt; which is forwarded in the previous step, you can connect to your database and execute commands there!&lt;/p&gt;

&lt;p&gt;At last, don't forget to close your forwarding command!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Using an SSH tunnel and Docker, we can connect to our remote database easily.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds"&gt;https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>database</category>
      <category>ssh</category>
    </item>
    <item>
      <title>Keep your code format clean using prettier</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sat, 31 Aug 2019 09:08:33 +0000</pubDate>
      <link>https://forem.com/danimal141/keep-your-code-format-clean-using-prettier-40</link>
      <guid>https://forem.com/danimal141/keep-your-code-format-clean-using-prettier-40</guid>
      <description>&lt;p&gt;I recently used &lt;a href="https://github.com/prettier/prettier"&gt;&lt;code&gt;prettier&lt;/code&gt;&lt;/a&gt; to keep my team's code format clean, then I felt it worked well.&lt;/p&gt;

&lt;p&gt;This post introduces how to use &lt;code&gt;prettier&lt;/code&gt; in a team.&lt;/p&gt;

&lt;h2&gt;
  
  
  What kind of project do we start?
&lt;/h2&gt;

&lt;p&gt;As an example, let's think about a situation we will create a git repository and write a lot of markdown documentation, and anyone can contribute to the repository.&lt;/p&gt;

&lt;p&gt;We surely want to keep the code format clean and consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install &lt;code&gt;prettier&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Following &lt;a href="https://prettier.io/docs/en/install.html"&gt;this documentation&lt;/a&gt;, we can install &lt;code&gt;prettier&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this post, I use &lt;code&gt;yarn&lt;/code&gt; to install it.&lt;br&gt;
All we have to do is executing &lt;code&gt;yarn add prettier --dev --exact&lt;/code&gt; in the project root.&lt;/p&gt;

&lt;p&gt;After that, we would get &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;yarn.lock&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to use &lt;code&gt;prettier&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To try to use &lt;code&gt;prettier&lt;/code&gt;, Let's update &lt;code&gt;package.json&lt;/code&gt; like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prettier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier *.md --write"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prettier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And please prepare a dirty sample markdown like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;touch &lt;/span&gt;test.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Test&lt;/span&gt;

&lt;span class="gu"&gt;## testtest&lt;/span&gt;

This is a test!
&lt;span class="p"&gt;
-&lt;/span&gt; test1
&lt;span class="p"&gt;-&lt;/span&gt; test2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then let's invoke &lt;code&gt;yarn prettier&lt;/code&gt;.&lt;br&gt;
After that, the sample file's format would become clean like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Test&lt;/span&gt;

&lt;span class="gu"&gt;## testtest&lt;/span&gt;

This is a test!
&lt;span class="p"&gt;
-&lt;/span&gt; test1
&lt;span class="p"&gt;-&lt;/span&gt; test2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this post, I will use the default configuration, but if you would like to configure, please refer to &lt;a href="https://prettier.io/docs/en/configuration.html"&gt;this documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;prettier&lt;/code&gt; on CI to validate the code format
&lt;/h3&gt;

&lt;p&gt;Currently, to keep the code format clean, everyone has to always execute &lt;code&gt;yarn prettier&lt;/code&gt; while modifying files. I feel it's very easy to forget.&lt;/p&gt;

&lt;p&gt;To notice some format is unexpected soon, let's use CI.&lt;/p&gt;

&lt;p&gt;At first, to check the code format, we can use &lt;code&gt;prettier --check&lt;/code&gt;. Let's add another command to &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prettier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier *.md --write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lint:prettier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prettier --check *.md"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prettier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To review the code each other, we basically use GitHub or something like that. Then we can invoke the validation command in every pull request via CI like CircleCI.&lt;/p&gt;

&lt;p&gt;This is sample CircleCI configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; .circleci &amp;amp; &lt;span class="nb"&gt;touch&lt;/span&gt; .circleci/config.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/node:10&lt;/span&gt;
    &lt;span class="na"&gt;working_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/repo&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;v1-dependencies-{{ checksum "yarn.lock" }}&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;v1-dependencies-&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1-dependencies-{{ checksum "yarn.lock" }}&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prettier&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn lint:prettier&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After integrating GitHub and CircleCI, we can ensure the code format (if some format is unexpected, the CI fails).&lt;/p&gt;

&lt;p&gt;To contribute to the project, &lt;code&gt;yarn prettier&lt;/code&gt; is a must for everyone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;prettier&lt;/code&gt; is very convenient and easy to use.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;prettier&lt;/code&gt; on CI, we would be able to keep our code clean more robustly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/prettier/prettier"&gt;https://github.com/prettier/prettier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://prettier.io/docs/en/"&gt;https://prettier.io/docs/en/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>prettier</category>
    </item>
    <item>
      <title>Create an SFTP server with AWS Transfer for SFTP</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sun, 07 Jul 2019 09:58:26 +0000</pubDate>
      <link>https://forem.com/danimal141/create-sftp-server-with-aws-transfer-for-sftp-1a7l</link>
      <guid>https://forem.com/danimal141/create-sftp-server-with-aws-transfer-for-sftp-1a7l</guid>
      <description>&lt;p&gt;This post describes how to create an SFTP server on AWS (AWS Transfer for SFTP).&lt;br&gt;
About the overview of AWS Transfer for SFTP, please refer to &lt;a href="https://aws.amazon.com/sftp/?nc1=h_ls" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide SFTP Configuration
&lt;/h2&gt;

&lt;p&gt;AWS SFTP can configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS configuration

&lt;ul&gt;
&lt;li&gt;"None" or "Amazon Route53 DNS alias"&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Identity provider

&lt;ul&gt;
&lt;li&gt;"Service Managed" or "Custom"&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Logging role&lt;/li&gt;

&lt;li&gt;Tags&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In this post, I decided to configure like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS configuration

&lt;ul&gt;
&lt;li&gt;"None" (Use an endpoint name which AWS creates directly)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Identity provider

&lt;ul&gt;
&lt;li&gt;"Service Managed" (Use the AWS SFTP feature)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Logging role and Tags are not used in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare S3 bucket for SFTP server
&lt;/h2&gt;

&lt;p&gt;AWS SFTP requires an S3 bucket, so let's prepare your bucket first.&lt;/p&gt;

&lt;p&gt;In this post, I prepared a bucket named &lt;code&gt;danimal141-sftp-test&lt;/code&gt;, which has a folder named &lt;code&gt;test&lt;/code&gt; as an example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create CloudFormation template
&lt;/h2&gt;

&lt;p&gt;To achieve creating an SFTP server, we should do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an IAM policy&lt;/li&gt;
&lt;li&gt;Create an IAM role&lt;/li&gt;
&lt;li&gt;Create an SFTP server&lt;/li&gt;
&lt;li&gt;Create an SFTP user

&lt;ul&gt;
&lt;li&gt;It has the above IAM role&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There are many dependencies, so let's use AWS CloudFormation to make the process easier.&lt;br&gt;
The template becomes like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2010-09-09'&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;SftpAccessPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::ManagedPolicy&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SftpAccessPolicy&lt;/span&gt;
      &lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sftp access policy&lt;/span&gt;
      &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2012-10-17'&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:PutObject'&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:GetObject'&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:DeleteObject'&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:GetObjectVersion'&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:DeleteObjectVersion'&lt;/span&gt;
            &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:::danimal141-sftp-test/test/*'&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:ListBucket'&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:GetBucketLocation'&lt;/span&gt;
            &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:::danimal141-sftp-test'&lt;/span&gt;
            &lt;span class="na"&gt;Condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;StringLike&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:prefix'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test/*'&lt;/span&gt;

  &lt;span class="na"&gt;SftpAccessRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2012-10-17'&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Allow'&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;transfer.amazonaws.com'&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sts:AssumeRole'&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyArns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;SftpAccessPolicy&lt;/span&gt;

  &lt;span class="na"&gt;SftpServer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Transfer::Server&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;EndpointType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PUBLIC&lt;/span&gt;

  &lt;span class="na"&gt;SftpUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Transfer::User&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;UserName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;testuser&lt;/span&gt;
      &lt;span class="na"&gt;HomeDirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/danimal141-sftp-test/test'&lt;/span&gt;
      &lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;SftpAccessRole.Arn&lt;/span&gt;
      &lt;span class="na"&gt;ServerId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;SftpServer.ServerId&lt;/span&gt;
      &lt;span class="na"&gt;SshPublicKeys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;YOUR PUBLIC KEY&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;About IAM policies and roles for SFTP, you could refer to &lt;a href="https://docs.aws.amazon.com/transfer/latest/userguide/requirements-roles.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create CloudFormation stack
&lt;/h2&gt;

&lt;p&gt;Let's create a CloudFormation stack with the above template on the AWS console or &lt;code&gt;aws cloudformation&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2xlqwp9ys8zl1bhfmvgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2xlqwp9ys8zl1bhfmvgk.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The important point is that the process requires capabilities: &lt;code&gt;[AWS::IAM::ManagedPolicy, AWS::IAM::Role]&lt;/code&gt;.&lt;br&gt;
We should acknowledge that CloudFormation might create IAM resources with custom names.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfla9wzy7odpjlc4a1lx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfla9wzy7odpjlc4a1lx.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After finishing creating the stack successfully, you would be able to see the SFTP server on the AWS console!&lt;br&gt;
And then, you can check the server with &lt;code&gt;sftp&lt;/code&gt; command like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

sftp &lt;span class="nt"&gt;-i&lt;/span&gt; your_ssh_key your_user_name@server_endpoint

sftp&amp;gt; &lt;span class="nb"&gt;pwd
&lt;/span&gt;Remote working directory: /danimal141-sftp/test

sftp&amp;gt; put index.html
Uploading index.html to /danimal141-sftp-test/test/index.html

sftp&amp;gt; &lt;span class="nb"&gt;rm &lt;/span&gt;index.html
Removing /danimal141-sftp-test/test/index.html

sftp&amp;gt; &lt;span class="nb"&gt;exit&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Of course, you could also use an app like Cyberduck or something like that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean up dependencies
&lt;/h2&gt;

&lt;p&gt;Please be careful of forgetting removing the SFTP server, because you are billed on an hourly basis from the time you create and configure your SFTP server, which is provisioned for your dedicated use, until the time you delete the server (Reference: &lt;a href="https://aws.amazon.com/jp/sftp/pricing/" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;If you use CloudFormation like the above example, it's dead easy to clean up all dependencies.&lt;br&gt;
All you have to do is just deleting the CloudFormation stack!&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We can create an SFTP server easily with AWS Transfer for SFTP.&lt;/li&gt;
&lt;li&gt;We can create and delete stuff related to the SFTP server easily with AWS CloudFormation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/sftp/?nc1=h_ls" rel="noopener noreferrer"&gt;https://aws.amazon.com/sftp/?nc1=h_ls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/transfer/latest/userguide/requirements-roles.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/transfer/latest/userguide/requirements-roles.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/jp/sftp/pricing" rel="noopener noreferrer"&gt;https://aws.amazon.com/jp/sftp/pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>cloudformation</category>
      <category>sftp</category>
      <category>iam</category>
    </item>
    <item>
      <title>How to investigate memory usage on ElastiCache for Redis</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sat, 15 Jun 2019 08:42:08 +0000</pubDate>
      <link>https://forem.com/danimal141/how-to-investigate-memory-usage-on-elasticache-for-redis-5dm5</link>
      <guid>https://forem.com/danimal141/how-to-investigate-memory-usage-on-elasticache-for-redis-5dm5</guid>
      <description>&lt;p&gt;Recently, I faced a problem which memory usage on ElastiCache for Redis becomes huge.&lt;br&gt;
This post describes how we can investigate such a problem (which keys are bottlenecks on ElastiCache).&lt;/p&gt;
&lt;h2&gt;
  
  
  Export and download a Redis backup
&lt;/h2&gt;

&lt;p&gt;At first, to analyze, we have to download the &lt;code&gt;.rdb&lt;/code&gt; file from our ElastiCache following &lt;a href="https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/backups-exporting.html"&gt;the official guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When exporting an ElastiCache backup, please be careful that the region for S3 must be the same as the one for the backup.&lt;/p&gt;
&lt;h2&gt;
  
  
  Analyze &lt;code&gt;.rdb&lt;/code&gt; with redis-rdb-tools
&lt;/h2&gt;

&lt;p&gt;After downloading the file, we can analyze it with &lt;a href="https://github.com/sripathikrishnan/redis-rdb-tools"&gt;redis-rdb-tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, if we wanna generate a memory report, we can do it as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rdb &lt;span class="nt"&gt;-c&lt;/span&gt; memory /var/redis/6379/dump.rdb &lt;span class="nt"&gt;--bytes&lt;/span&gt; 128 &lt;span class="nt"&gt;-f&lt;/span&gt; memory.csv
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;memory.csv

database,type,key,size_in_bytes,encoding,num_elements,len_largest_element
0,list,lizards,241,quicklist,5,19
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your &lt;code&gt;.rdb&lt;/code&gt; is too large (it may be difficult to open the csv file), you could also generate a sampled report like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rdb &lt;span class="nt"&gt;-c&lt;/span&gt; memory /var/redis/6379/dump.rdb | ruby &lt;span class="nt"&gt;-ne&lt;/span&gt; &lt;span class="s1"&gt;'print $_ if rand &amp;lt; 0.1'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; memory.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, &lt;code&gt;redis-rdb-tools&lt;/code&gt; supports features other than generating a memory report.&lt;br&gt;
For more information, please see the &lt;a href="https://github.com/sripathikrishnan/redis-rdb-tools"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We can export and download a backup file easily with ElastiCache and S3.&lt;/li&gt;
&lt;li&gt;We can analyze a &lt;code&gt;.rdb&lt;/code&gt; file easily with a tool like &lt;code&gt;redis-rdb-tools&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/backups-exporting.html"&gt;https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/backups-exporting.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sripathikrishnan/redis-rdb-tools"&gt;https://github.com/sripathikrishnan/redis-rdb-tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redis</category>
      <category>aws</category>
      <category>elasticache</category>
    </item>
    <item>
      <title>Flattening a nested hash to a single hash in Ruby</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sun, 09 Jun 2019 13:39:53 +0000</pubDate>
      <link>https://forem.com/danimal141/flattening-a-nested-hash-to-a-single-hash-in-ruby-2o1j</link>
      <guid>https://forem.com/danimal141/flattening-a-nested-hash-to-a-single-hash-in-ruby-2o1j</guid>
      <description>&lt;p&gt;When using Ruby, you may sometimes need to flatten a nested hash like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;:foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:hello&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="ss"&gt;:world&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="ss"&gt;:bro&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"What's up dude?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="ss"&gt;:a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;:c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"d"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to a single hash like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="ss"&gt;:foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:"hello.world"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:"hello.bro"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"What's up dude?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:"a.b.c"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"d"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Today, I introduce a way to achieve it referring to &lt;a href="https://stackoverflow.com/questions/23521230/flattening-nested-hash-to-a-single-hash-with-ruby-rails"&gt;a post in Stack Overflow&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s implement
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;flatten_hash_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_object&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="n"&gt;flatten_hash_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;intern&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;
    &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;Enumberable#each_with_object&lt;/code&gt; recursively helps us achieve it.&lt;br&gt;
Let’s deep dive into how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, &lt;code&gt;key = :foo&lt;/code&gt;, &lt;code&gt;value = "bar"&lt;/code&gt; is given. the value is not a hash, so &lt;code&gt;memo&lt;/code&gt; becomes &lt;code&gt;{ :foo =&amp;gt; "bar" }&lt;/code&gt; and the process continues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;key = :hello&lt;/code&gt;, &lt;code&gt;value = { :world =&amp;gt; "Hello World", :bro =&amp;gt; "What's up dude?" }&lt;/code&gt; is given. The value is a hash, so &lt;code&gt;flatten_hash_from&lt;/code&gt; is invoked again with the value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After STEP 2, &lt;code&gt;memo&lt;/code&gt; is &lt;code&gt;{}&lt;/code&gt; again, which is different from the one in STEP 1. Then, &lt;code&gt;key = :world&lt;/code&gt;, &lt;code&gt;value = "Hello World"&lt;/code&gt; is given, which is not a hash, so &lt;code&gt;memo&lt;/code&gt; becomes &lt;code&gt;{ :world =&amp;gt; "Hello World" }&lt;/code&gt;. Similarly, &lt;code&gt;key = :bro&lt;/code&gt; is given next, then &lt;code&gt;memo&lt;/code&gt; becomes &lt;code&gt;{ :world =&amp;gt; "Hello World", :bro =&amp;gt; "What's up dude?" }&lt;/code&gt; and the result is returned to STEP 2.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From STEP 3, the process goes back to &lt;code&gt;each&lt;/code&gt; part with &lt;code&gt;key = :hello&lt;/code&gt;. By &lt;code&gt;memo["#{key}.#{k}".intern] = v&lt;/code&gt;, &lt;code&gt;memo&lt;/code&gt; becomes &lt;code&gt;{ :foo =&amp;gt; "bar", :"hello.world" =&amp;gt; "Hello World", :"hello.bro" =&amp;gt; "What's up dude?" }&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, &lt;code&gt;key = :a&lt;/code&gt;, &lt;code&gt;value = { :b =&amp;gt; { :c =&amp;gt; "d" } }&lt;/code&gt; is given. The value is a hash then, &lt;code&gt;flatten_hash_from&lt;/code&gt; is invoked recursively like STEP2.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;flatten_hash_from&lt;/code&gt; is invoked with &lt;code&gt;key = :b&lt;/code&gt;, &lt;code&gt;value = { :c =&amp;gt; "d" }&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;{ :c =&amp;gt; "d" }&lt;/code&gt; is returned to STEP 6.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;{ :"b.c" =&amp;gt; "d" }&lt;/code&gt; is returned to STEP 5.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From STEP 5, the process goes back to &lt;code&gt;each&lt;/code&gt; part with &lt;code&gt;key = :a&lt;/code&gt; and &lt;code&gt;{ :"a.b.c" =&amp;gt; "d" }&lt;/code&gt; is added to &lt;code&gt;memo&lt;/code&gt;. It turns out &lt;code&gt;memo&lt;/code&gt; is &lt;code&gt;{ :foo =&amp;gt; "bar", :"hello.world" =&amp;gt; "Hello World", :"hello.bro" =&amp;gt; "What's up dude?", :"a.b.c" =&amp;gt; "d" }&lt;/code&gt;, then the process completed.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/23521230/flattening-nested-hash-to-a-single-hash-with-ruby-rails"&gt;https://stackoverflow.com/questions/23521230/flattening-nested-hash-to-a-single-hash-with-ruby-rails&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
    </item>
    <item>
      <title>active_model_serializers with PORO (Plain-Old Ruby Object)</title>
      <dc:creator>Hideaki Ishii</dc:creator>
      <pubDate>Sun, 09 Jun 2019 13:22:07 +0000</pubDate>
      <link>https://forem.com/danimal141/activemodelserializers-with-poro-plain-old-ruby-object-20ij</link>
      <guid>https://forem.com/danimal141/activemodelserializers-with-poro-plain-old-ruby-object-20ij</guid>
      <description>&lt;p&gt;Recently, I worked on a Rails API project.&lt;/p&gt;

&lt;p&gt;In the project, I fetched external data and made POROs which were compliant with &lt;a href="https://github.com/rails-api/active_model_serializers"&gt;active_model_serializers&lt;/a&gt; with the data.&lt;br&gt;
Then our APIs returned the POROs serialized.&lt;/p&gt;

&lt;p&gt;Today, I introduce the development flow a little bit.&lt;/p&gt;
&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rails 6.0.0.beta3&lt;/li&gt;
&lt;li&gt;active_model_serializers 0.10.9&lt;/li&gt;
&lt;li&gt;factory_bot 5.0.2&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Directory structure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;app/models

&lt;ul&gt;
&lt;li&gt;POROs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;app/serializers

&lt;ul&gt;
&lt;li&gt;Serializers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;app/controllers

&lt;ul&gt;
&lt;li&gt;Endpoints&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Model
&lt;/h2&gt;

&lt;p&gt;As an example, let’s consider &lt;code&gt;Image&lt;/code&gt; model which has a URL and size information.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;active_model_serializers&lt;/code&gt; provides &lt;code&gt;ActiveModelSerializers::Model&lt;/code&gt; for POROs like &lt;a href="https://github.com/rails-api/active_model_serializers/tree/0-10-stable#what-does-a-serializable-resource-look-like"&gt;this&lt;/a&gt;, which is so easy to use.&lt;/p&gt;

&lt;p&gt;If you need to deal with a more complicated case, you would be able to implement and use a model which is compliant with &lt;a href="https://github.com/rails-api/active_model_serializers/blob/0-10-stable/lib/active_model/serializer/lint.rb"&gt;this specification&lt;/a&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/image.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Image&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveModelSerializers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Model&lt;/span&gt;
  &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:size&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# app/models/image/size.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Image::Size&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveModelSerializers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Model&lt;/span&gt;
  &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="ss"&gt;:width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:height&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Serializer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/serializers/image_serializer.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImageSerializer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Serializer&lt;/span&gt;
  &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:type&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:size&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# app/serializers/image/size_serializer.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Image::SizeSerializer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Serializer&lt;/span&gt;
  &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="ss"&gt;:width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:height&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defining relations like &lt;code&gt;has_one&lt;/code&gt;, we can use &lt;a href="https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/adapters.md#include-option"&gt;include option&lt;/a&gt; conveniently on endpoints.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;render json: image, include: '*'&lt;/code&gt; returns JSON including &lt;code&gt;size&lt;/code&gt; and &lt;code&gt;render json: image, include: ''&lt;/code&gt; returns JSON without &lt;code&gt;size&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Controller
&lt;/h2&gt;

&lt;p&gt;We can use serializers easily in controllers. All we have to do is create a model instance and pass it to &lt;code&gt;render&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;active_model_serializers&lt;/code&gt; finds a suitable serializer for an instance given and serialize it, and the response returns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/controllers/v1/images_controller.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;V1&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ImagesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;include: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:include&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;private&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;image&lt;/span&gt;
      &lt;span class="vi"&gt;@image&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_attrs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;image_attrs&lt;/span&gt;
      &lt;span class="vi"&gt;@image_attrs&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;fetch_data_somehow&lt;/span&gt; &lt;span class="c1"&gt;# Fetch external data&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;When testing &lt;code&gt;ActiveRecord&lt;/code&gt; models, we can use &lt;code&gt;factory_bot&lt;/code&gt; and make the factories like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; user = FactoryBot.create(:user)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in this case, &lt;code&gt;FactoryBot#create&lt;/code&gt; does not work well because there is no store (in addition, it’s not needed to store them).&lt;/p&gt;

&lt;p&gt;Plus, &lt;code&gt;ActiveModelSerializers::Model&lt;/code&gt; is based on &lt;code&gt;ActiveModel&lt;/code&gt;, so the initializer requires a hash named &lt;code&gt;attributes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we omit the argument &lt;code&gt;attributes&lt;/code&gt;, &lt;code&gt;attributes = {}&lt;/code&gt; will be given as the default, then serialization does not work well expectedly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/factories/images.rb&lt;/span&gt;
&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:image&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:image_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# spec/factories/image/sizes.rb&lt;/span&gt;
&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:image_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'Image::Size'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; image = FactoryBot.create(:image)
=&amp;gt; NoMethodError: undefined method `save!`...

&amp;gt; image = FactoryBot.build(:image)
&amp;gt; image.attributes
=&amp;gt; {}

&amp;gt; image.to_json
=&amp;gt; "{}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;factory_bot&lt;/code&gt; provides &lt;a href="https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#custom-construction"&gt;initialize_with&lt;/a&gt; to override initializers.&lt;/p&gt;

&lt;p&gt;Also, it provides &lt;a href="https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#custom-methods-to-persist-objects"&gt;skip_create&lt;/a&gt; to skip creation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/factories/images.rb&lt;/span&gt;
&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:image&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;skip_create&lt;/span&gt;
    &lt;span class="n"&gt;initalize_with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:image_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# spec/factories/image/sizes.rb&lt;/span&gt;
&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:image_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s1"&gt;'Image::Size'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;skip_create&lt;/span&gt;
    &lt;span class="n"&gt;initalize_with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; image = FactoryBot.create(:image)
=&amp;gt; #&amp;lt;Image:...&amp;gt; The result is the same as one from `build`🙌

&amp;gt; image = FactoryBot.build(:image)
&amp;gt; image.attributes
=&amp;gt; { "url" =&amp;gt; ..., "size" =&amp;gt; ... }

&amp;gt; image.to_json
=&amp;gt; "{\"url\":...,\"size\":...}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid writing &lt;code&gt;initialize_with&lt;/code&gt; and &lt;code&gt;skip_create&lt;/code&gt; many times, I eventually prepared a specific DSL like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;defined?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;FactoryBot&lt;/span&gt;
    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Syntax&lt;/span&gt;
      &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Default&lt;/span&gt;
        &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DSL&lt;/span&gt;
          &lt;span class="c1"&gt;# Custom DSL for ActiveModelSerializers::Model&lt;/span&gt;
          &lt;span class="c1"&gt;# Original: https://github.com/thoughtbot/factory_bot/blob/v5.0.2/lib/factory_bot/syntax/default.rb#L15-L26&lt;/span&gt;
          &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;serializers_model_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;proxy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DefinitionProxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;block_given?&lt;/span&gt;
              &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instance_eval&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
                &lt;span class="n"&gt;skip_create&lt;/span&gt;
                &lt;span class="n"&gt;initialize_with&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="nb"&gt;instance_eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="k"&gt;end&lt;/span&gt;
            &lt;span class="k"&gt;end&lt;/span&gt;
            &lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;proxy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;child_factories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
              &lt;span class="n"&gt;parent_factory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;child_options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
              &lt;span class="n"&gt;serializers_model_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;child_options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;parent: &lt;/span&gt;&lt;span class="n"&gt;parent_factory&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;child_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;end&lt;/span&gt;
          &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The factory implementation turned out like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/factories/images.rb&lt;/span&gt;
&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;serializers_model_factory&lt;/span&gt; &lt;span class="ss"&gt;:image&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;Faker&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Internet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:image_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can use it in specs easily like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/serializers/image_serializer_spec.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;ImageSerializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :serializer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:resource&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="no"&gt;ActiveModelSerializers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SerializableResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;include: &lt;/span&gt;&lt;span class="s1"&gt;'*'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'#url'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serializable_hash&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;is_expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We can use &lt;code&gt;active_model_serializers&lt;/code&gt; without &lt;code&gt;ActiveRecord&lt;/code&gt; easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rails-api/active_model_serializers/tree/0-10-stable#what-does-a-serializable-resource-look-like"&gt;https://github.com/rails-api/active_model_serializers/tree/0-10-stable#what-does-a-serializable-resource-look-like&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/adapters.md#include-option"&gt;https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/adapters.md#include-option&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md"&gt;https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>testing</category>
      <category>activemodel</category>
    </item>
  </channel>
</rss>
