<?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>DEV Community: André Perdigão</title>
    <description>The latest articles on DEV Community by André Perdigão (@andrepcg).</description>
    <link>https://dev.to/andrepcg</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%2F60551%2Fb090f900-573c-4faf-8d17-5c2ba2f68b3f.jpeg</url>
      <title>DEV Community: André Perdigão</title>
      <link>https://dev.to/andrepcg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andrepcg"/>
    <language>en</language>
    <item>
      <title>Building Roasted.email - Temporary emails and phone numbers</title>
      <dc:creator>André Perdigão</dc:creator>
      <pubDate>Sun, 05 Jul 2020 13:51:49 +0000</pubDate>
      <link>https://dev.to/andrepcg/building-roasted-email-temporary-emails-and-phone-numbers-3g48</link>
      <guid>https://dev.to/andrepcg/building-roasted-email-temporary-emails-and-phone-numbers-3g48</guid>
      <description>&lt;p&gt;See it live @ &lt;a href="https://roasted.email"&gt;https://roasted.email&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, temporary emails are not by any chance a new idea. There are a bunch of free services that generate an email for you and let you use the inbox to receive emails for websites you don't want to give your personal one.&lt;/p&gt;

&lt;p&gt;So I wanted to build my own essentially to find out how mail servers work, such as postfix or exim. Long story short, the service is live and I still don't know much about postix :( I struggled a bit configuring email forwarding coming from multiple domains. Now the service is live maybe I can have more time to actually find how it works and also use Rails Action Mailbox. &lt;a href="https://dev.to/truemark/setup-action-mailbox-with-postfix-part-2-300b"&gt;This guide&lt;/a&gt; seems to be good.&lt;/p&gt;

&lt;p&gt;By not using my own mail server, I'm using Sendgrid's Parse API. It's very easy to setup, you just need to add Sendgrid's DNS entries to your domains and set the endpoint URL where Sendgrid POSTs the email and voila! One interesting thing is that Sendgrid doesn't talk in their docs it's requests validation (from what I could find). So one way I added a bit of security to the webhook endpoint is to validate if the IP belongs to Sendgrid. You can find Sendgrid's IP ranges &lt;a href="https://bgp.he.net/AS11377#_prefixes"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When it comes to the Rails app, it's pretty simple. There's just a handful of models and controllers. I also wanted to use pure Rails without any frontend framework (such as React) and for that &lt;a href="https://guides.rubyonrails.org/working_with_javascript_in_rails.html"&gt;UJS&lt;/a&gt; was handy.&lt;/p&gt;

&lt;p&gt;I also wanted to make it super simple for the user, with just one click he can generate an inbox and it's ready to use.&lt;/p&gt;

&lt;p&gt;One suggestion I got from a few friends was to also provide temporary phone numbers. That was an interesting addition to the project and I've described the approach &lt;a href="https://andrepcg.top/temporary-phone-numbers-roasted-email/"&gt;on my blog&lt;/a&gt;. Essentially, it's easy to achieve that using Twilio but for Portuguese phone numbers it's too expensive ($15/month to keep a number) and I opted for a custom solution using pre-paid SIM cards. Regarding Twilio, it works very similarly to Sendgrid. When an SMS is received by Twilio, they POST to a Webhook and Rails parses the request.&lt;/p&gt;

&lt;p&gt;For now it has been an interesting project. It's not by any chance a complex topic but cool non the least.&lt;/p&gt;

&lt;p&gt;Btw, it's open source: &lt;a href="https://github.com/andrepcg/roasted-mail"&gt;https://github.com/andrepcg/roasted-mail&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>sms</category>
      <category>twilio</category>
    </item>
    <item>
      <title>Using Scenic and SQL views to aggregate data</title>
      <dc:creator>André Perdigão</dc:creator>
      <pubDate>Thu, 29 Nov 2018 14:48:56 +0000</pubDate>
      <link>https://dev.to/weareredlight/using-scenic-and-sql-views-to-aggregate-data-226k</link>
      <guid>https://dev.to/weareredlight/using-scenic-and-sql-views-to-aggregate-data-226k</guid>
      <description>&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Ae5GfybqgP5aCH08hYcEVGg.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2Ae5GfybqgP5aCH08hYcEVGg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Ruby on Rails (RoR) community is known to be large and established and takes great benefit one of the largest packages repository, RubyGems, serving 147k packages at the time of writing this article.&lt;/p&gt;

&lt;p&gt;This short intro also meant to say that there’s almost one package for any need you might have, and this was the case I ran into with  &lt;a href="https://github.com/thoughtbot/scenic" rel="noopener noreferrer"&gt;&lt;strong&gt;Scenic&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By using a standard RDBMS (relational database) we split different kinds of data into its own table and keep it normalized. Down the line, getting a specific set of data can get a bit tricky as more tables were created and the data is now even more split up.&lt;/p&gt;

&lt;p&gt;Let’s get practical now.&lt;/p&gt;

&lt;p&gt;Suppose we have the following database structure:&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A9rCeKOWtHnSW1xDC1qoMKg.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2A9rCeKOWtHnSW1xDC1qoMKg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a project grows, new kinds of tables can be created and the relationships also grow.&lt;/p&gt;

&lt;p&gt;The complexity arises when trying to query and filter data and respective associations while using ActiveRecord. As a first step we could do something like (assuming all relations are specified in the model):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data  
  .joins(:people, :tasks, task: :project, task: { project: :organization }, ...)  
  .where(tasks: { projects: { organization_id: [] } })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The number of joins can grow out of hand and WHERE selections can also be difficult to construct. Every time you need to apply the same kind of filter you need to join everything again and navigate your way with  &lt;em&gt;where&lt;/em&gt;, building the query all over again_._&lt;/p&gt;

&lt;p&gt;Before showing a simpler solution let’s talk about SQL Views:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Views can represent a subset of the data contained in a table;&lt;/li&gt;
&lt;li&gt; Views can join and simplify multiple tables into a  &lt;strong&gt;single virtual table&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt; Views can  &lt;strong&gt;act as aggregated tables&lt;/strong&gt;, where the database engine aggregates data (sum, average, etc) and presents the calculated results as part of the data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short, a View is query turned into a  &lt;em&gt;virtual&lt;/em&gt;  &lt;em&gt;table&lt;/em&gt;  that can be queried. On the other hand, a materialized view is a View that gets actually persisted as a table and needs to be refreshed for its values to get updated (good for long queries, pre-calculating data)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/thoughtbot/scenic" rel="noopener noreferrer"&gt;&lt;strong&gt;Scenic&lt;/strong&gt;&lt;/a&gt;  gives you a way to define SQL views in Rails, with migrations and SQL code. Its purpose is to help you define SQL views in a maintainable way.&lt;/p&gt;

&lt;p&gt;Resuming the example above, if we wanted to define a query where we could filter for PersonType, Task (and respective name), Project, Organization and Client we could write something like:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT  
  d.id as data_id,  
  d.person_id AS person_id,  
  t.name AS task_name,  
  t.project_id AS project_id,  
  pt.type AS person_type,  
  p.organization_id AS organization_id,  
  p.client_id AS client_id  
FROM data d  
LEFT JOIN people ON d.person_id = people.id  
LEFT JOIN person_types pt ON people.person_type_id = pt.id  
LEFT JOIN tasks t ON d.task_id = t.id  
LEFT JOIN projects p ON t.project_id = p.id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Inspecting the above structure as a simple table we get:&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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AdQTH-WIkSOACXmo752nWxQ.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%2Fcdn-images-1.medium.com%2Fmax%2F1600%2F1%2AdQTH-WIkSOACXmo752nWxQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That SQL code is defined in its own file and used by the respective migration. The SQL view can be updated by running the Scenic task again for the same view name and it auto generates a new SQL file and migration to update the view.&lt;/p&gt;

&lt;p&gt;I can now  &lt;strong&gt;use this table (&lt;em&gt;view&lt;/em&gt;) to back a model&lt;/strong&gt;, that’s the beauty of Scenic.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DataAggregate &amp;lt; ApplicationRecord  
  belongs_to :data

  self.primary_key = 'data_id'

  def readonly?  
    true  
  end  
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And use the &lt;em&gt;DataAggregate&lt;/em&gt; model as any other ActiveRecord model. Now I could write my filtering queries as:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data = Data.joins(:data_aggregate)  
data = data.where('organization_id IN (?)', filters.org_ids) if filters.org_ids.present?  
data = data.where('client_id IN (?)', filters.client_ids) if filters.client_ids.present?  
data = data.where('project_id IN (?)', filters.project_ids) if filters.project_ids.present?  
data = data.where('person_id IN (?)', filters.user_ids) if filters.user_ids.present?  
data = data.where('task_id IN (?)', filters.task_ids) if filters.task_ids.present?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;By joining Data with DataAggregate I get the original Data table columns and all the other ones from DataAggregate, and thus being able to further write simpler  &lt;em&gt;where&lt;/em&gt;  queries with ActiveRecord.&lt;/p&gt;

&lt;p&gt;We could also define a scope to join the data and just use  &lt;code&gt;Data.with_aggregates&lt;/code&gt; .&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scope :with_aggregates do  
  joins(:data_aggregate)  
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;One other powerful use case for Scenic is materialized views. I could define a view that is very time consuming to generate (complex SQL query with many aggregations and joins) and refresh it from time to time or on demand. This could be helpful to reduce load times by displayed cached/pre-computed calculations.&lt;/p&gt;

&lt;p&gt;If you want to play around with the previous database structure and data just check the Database/SQL fiddle at  &lt;a href="https://www.db-fiddle.com/f/ojLiDMLRajXXhhGqzi3P26/0" rel="noopener noreferrer"&gt;https://www.db-fiddle.com/f/ojLiDMLRajXXhhGqzi3P26/0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Read our previous blog post on  &lt;a href="https://blog.weareredlight.com/el-cheapo-rails-performance-metrics-part-1-d05bc4c03456" rel="noopener noreferrer"&gt;Monitoring Rails Performance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also read the same post on our medium page: &lt;a href="https://blog.weareredlight.com/using-scenic-and-sql-views-to-aggregate-data-72861b75a0fd" rel="noopener noreferrer"&gt;https://blog.weareredlight.com/using-scenic-and-sql-views-to-aggregate-data-72861b75a0fd&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>programming</category>
      <category>sql</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
