Sean M

Joined

3,320 Experience
19 Lessons Completed
0 Questions Solved

Activity

Posted in Your biggest aha! moment?

I would recommend this book:

https://rebuilding-rails.com/

It explains in a simple way how the different parts of rails (ORM, routing, auto-require, rendering, etc.) work under the hood and on the top of that It's way easier to understand than rails source code.

Posted in rails5 + heroku + cloudfront + fonts

Hey Chris,

I didn't :(. This (https://github.com/equivalent/scrapbook2/blob/master/archive/blogs/2016-09-cors-rails-assets-cdn-heroku.md) seems to be quiet a resource, but didn't solve the problem with rails 5. If I set the allowed headers to my cloudfront distribution name then I get this error:

Access to Font at 'https://b33ef7kfsqfs9e.cloudfront.net/assets/fontawesome-webfont-7dacf83f51179de8d7980a513e67ab3a08f2c6272bb5946df8fd77c0d1763b73.woff2' from origin 'https://b33ef7kfsqfs9e.cloudfront.net' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'https://b33ef7kfsqfs9e.cloudfront.net' that is not equal to the supplied origin. Origin 'https://abcdef-staging.herokuapp.com' is therefore not allowed access.

This error is super weird because basically says https://b33ef7kfsqfs9e.cloudfront.net != https://b33ef7kfsqfs9e.cloudfront.net.

I have a few workarounds in mind like excluding fonts from cloudfront or uploading fonts to S3 (of course with cloudfront pointing to bucket) and adding the new source path in css files, but I would rather do the proper fix with allowed headers.

Posted in rails5 + heroku + cloudfront + fonts

I tried to configure a rails5 app (deployed on heroku) with cloudfront for assets and fonts. I could make it work for the assets, then I tried to add the config for the fonts as well, but I just screwed up everything and none of them works.

At the moment for the assets I get 404 error:

Failed to load resource:  xzy.cloudfront/assets/application-12341234.css the server   responded with a status of 404 ()

For the prev version when the assets worked but the fonts didn't, I got this error (I don't remember what was the diff between the 2 setup):

Access to Font at 'https://xyz.cloudfront.net/assets/fontawesome-webfont-7dacf83f51179de8d7980a513e67ab3a08f2c6272bb5946df8fd77c0d1763b73.woff2' from origin 'https://xyz.cloudfront.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://xzy.herokuapp.com' is therefore not allowed access.

I didn't really understand the problem because I thought I had everything properly configured:

production.rb

config.action_controller.asset_host = ENV['CLOUDFRONT_URL']
config.static_cache_control = 'public, max-age=31536000'

initializes/cors.rb (added the cors gem)

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
  origins '*'
  resource '/assets/*', headers: :any, methods: [:get]
  end
end

I likely didn't mess up the basic cloudfront config, because it was working before I started tweaking with the fonts. The behavior path pattern is set to default and it's connected to the herokuapp. The problem could be that the forwarded headers in the behavior are set like this:

Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Max-Age
Origin

As far as I know rails5 works with 12factors out of the box, so I don't have to add config.serve_static_assets = true if my RAILS_SERVE_STATIC_FILES env var is set to enabled (which happens automatically with heroku).

What did I miss? How can I make this work again?

Chris, when the server responses either to login action or any loggedin action later on how the token gets saved in the client browser (assuming you are using request.headers instead of params)? How does this differ from the html request version?

Posted in How to build REST APIs?

Chris, pls don't forget to add authentication to the API series. It would be great to see both devise/JWT implementation.

Posted in Group Chat with ActionCable: Part 7 Discussion

Thanks Chris for the quick answer. I know that it's not released yet, but I thought something could be done with acceptance test like this: http://bit.ly/2dfDTnC. But for some reason (likely actioncable related) I can't make it work. Do you have any idea?

Posted in Group Chat with ActionCable: Part 7 Discussion

Hey Chris,

I couldn't find good resources on how to test actioncable with rspec + capybara. Don't you know some great articles/repos I could check out?

Posted in How to build REST APIs?

Sounds great Chris!

Posted in How to build REST APIs?

Hey Chris,

When will you cover REST APIs? It would be great to see a series on that with some best practices. In today's email you wrote that you would cover Shrine uploads in detail soon, but since you have already made a few episodes on carrierwave and refile, this topic doesn't seem to be that exciting.

Hey Chris,
I tried to integrate the meta tag if else statement into the group chat app in the channels/chatrooms.js and got "cannot read property `send_message` of undefined" error. It was surprising since if I checked the val of the meta length it returned 1. It took some time to realize that you have to wrap this code into a `turbolinks:load` event since when the code gets to that point when send_message is invoked the meta tag length value is still 0.

Posted in Group Chat with ActionCable: Part 5 Discussion

Hey Chris,
With this code (no controller action and message creation happens in channel), what is the best way to authenticate the user for message creation? The only solution that comes into my mind is front-end authentication with currentUserId on the body tag and checking with jQuery if there is any number, I don't really like it. Is there a better approach at the moment?

Posted in Group Chat with ActionCable: Part 4 Discussion

Chris, how can you have you redis working without configuring and running the server in dev env? For me it raises "`rescue in establish_connection': Error connecting to Redis on localhost:6379 (Errno::ECONNREFUSED) (Redis::CannotConnectError)`" which is logical since the redis server is down.

Posted in rails vs node db transactions

Hi,

I am playing around with node.js and see promises everywhere even with db transactions. I was wondering why it is so different from rails.

For instance:

var db  = require('mongodb-promises').db('host:port', 'db_name'),
todoColl = db.collection('todos');

todoColl.insert({text: 'first task to do '})
  .then(function (result) {
    console.log('saved successfully');
  })
  .catch(function (err) {
    console.error('Error on insert ', err);
  });

in rails this would be something like

@todo = Todo.new(todo_params)
@todo.text = "first task to do"
if @todo.save
  render :json, @todo //I am not sure if format type matters in this example
else
  render json: @todo.errors, status: :unprocessable_entity
end

From my understanding (the following must be wrong somewhere, pls correct me):

Rails db transactions are synchronous and if @todo.save in controller is equivalent with after_save AR callback in the model, so rendering in controller fires after the validation is done and object is saved, BUT before it's committed to the database.

So basically we don't read the todo object from db after it gets there (since it's not committed yet), but we use @todo ivar which contains the knowledge to render html/json if data is valid and saved. Then if something goes wrong with the transaction then everything get's rolled back, so no problem. And we use after_commit instead of after_save in rails if we need some data that we wanna read back from db to make sure the data is already there (for instance elasticsearch indexing).

But my explanation must be wrong somewhere since if this is synchronous then we have to wait for the db transaction anyway, so we could use for instance if @todo.committed (this is just imaginary) or Todo.find(params(@todo.id)) instead of if @todo.save.

I. question:

Could you tell me where my explanation goes wrong?

II. As for node.js question:

Could you explain me why db transactions are handled asynchronously in node.js unlike in rails?

Posted in How to build REST APIs?

+1 :)

Posted in What to use for multistep(wizards) in 2016?

Hey Chris,

As of July 2016 what gem/solution would you use to create multistep forms? I have found a couple of solutions but couldn't decide what to choose. They kinda seemed a bit obsolete. It's also hard to decide if I should use some kind of state machine solution. Do you have some best practices?

Posted in 3rd party integration best practices/problems

Hey Chris!

I was wondering about the differences of the implementations of complex 3rd party integrations. For instance on the one hand there is segment.io or intercom.io. For these to work you need to track either with js or ruby the user actions. On the other hand there is for instance trello or slack integration where you send over data when user triggers a post/patch request like commenting on something or joining as team member. (Stripe or Braintree could be a 3rd example, where authentication/authorization is super crucial but those are documented well everywhere and you also made great screencasts on those)

Could you write a high level explanation what the main similarities and differences are? (design considerations (db tables/ models / controllers/ user flow), implementation problems, etc.) It would be also great to see some screencasts on these topics. I know this question is a bit broad, but I couldn't find good resources on this topic and having hard time figuring out how to integrate these.

Chris, another great one! You had 3 tests at the beginning for the 3 fee types. With having the code moved to the new classes would you write new tests or you think it's enough to have those 3 tests?

Posted in rails + DB dependent destroy vs cascade delete

Thanks Chris! I had this problem because of some foreign key constraint + not null combination in the db (without cascade delete), therefore parent couldn't be destroyed without destroying the child.

Then I will only keep the dependent: :destroy. I wanted to use both (like I do with validate presence and null: false) to make sure everything is synced, but it's not a good practice then in this case.

It would be great to see an episode on this. I mean something like 3-4 models that depend on each other, and the different options how this can be handled both on rails and DB side. For a simple instance there is a post and comment model and both have user_id. What if commenter deletes his account, but his old comments should be kept. If sby goes on the post page then it will raise an error since the commenter for that given comment doesn't exist anymore. (Because of this at the moment I have a dependent: :destroy chain on everything to make sure the app works fine.)

Posted in rails + DB dependent destroy vs cascade delete

Hi,

I wanna make sure that child objects also gets deleted when deleting parent.

I'd like to use both dependent: :destroy (rails side) and on_delete: :cascaade (db side). Is this a good practice or I should just stick with one. If just one which one should I choose?

has_many :conversations, dependent: :destroy  

add_foreign_key "conversations", "users", on_delete: :cascade

Posted in refactoring polymorphic actions

Hi Chris! I implemented the notification system based on your video with the partials. Works perfectly. I've got some problem though when user wanna check out the notification. When he/she clicks on the notification (either in dropdown or notification page) the following things must happen:

  • the checked_at attr gets set to current time (same for all types of notification)
  • the unchecked notification number gets decreased by 1 (same for all types of notification)
  • user gets redirected where the notification action happened (different for all types of notification)

At the moment I link every type of notification action (commented, accepted, etc.) to the custom checking_decreasing action route where first checked_at gets set and unchecked notification number gets decreased. Then based on the notification.notifiable_type and notification.action I redirect them to the desired page. So if sby commented on product then by clicking the notification you will get on that page. But as you see below there are so many combinations for redirecting that things got pretty messy in no time.

What kinda refactoring approach would you take here? I was thinking about creating a NotificationRedirectionsController where every notification_action + notifiable_type combination would have a separate action like def product_commented or def team_invitation_accepted etc. Is that a good idea? Do you know any refactoring technique for this case?

_commented.html.erb (same link in _commented.json.jbuilder

<%= link_to checking_decreasing_user_notifications_path(current_user, 
                                                        notifiable_type: notification.notifiable_type, 
                                                        notifiable_id: notification.notifiable_id, 
                                                        notification_action: notification.action
                                                        ) do %>

notifications controller / custom action

def checking_decreasing
  current_user.decreasing_comment_notification_number(params[:notifiable_type], 
                                                      params[:notifiable_id]
                                                      )
  redirect_to notification_redirection_path(params[:notifiable_type],
                                            params[:notifiable_id], 
                                            params[:notification_action]
                                            )
end

application controller

def notification_redirection_path(notifiable_type, notifiable_id, action)
  if action == "commented"
    if notifiable_type == "ProductCustomer"
      product_customer = ProductCustomer.find(notifiable_id)
      product_id = product_customer.product_id
    elsif notifiable_type == "ProductLead"
      product_lead = ProductLead.find(notifiable_id)
      product_id = product_lead.product_id
    end
    route = case notifiable_type
            when "Post"
              posts_path(anchor: "post_#{notifiable_id}")#{}"/posts#post_#{notifiable_id}"
            when "Product"
              product_path(notifiable_id, anchor: "comment-panel")#/products/#{notifiable_id}#comment-panel"
            when "ProductLead"
              product_product_lead_path(product_id, notifiable_id, anchor: "comment-panel")#{}"/products/#{product_id}/#{notifiable_type}/#{notifiable_id}#comment-panel"
            when "ProductCustomer"
              product_product_customer_path(product_id, notifiable_id, anchor: "comment-panel") #/products/#{product_id}/#{notifiable_type}/#{notifiable_id}#comment-panel"
            end
  elsif action == "invited"
    if notifiable_type == "Product"
      product_path(notifiable_id, anchor: "product-invitation-well")
    elsif notifiable_type == "ProductCustomer"
      product_customer = ProductCustomer.find(notifiable_id)
      product_id = product_customer.product_id
      product_product_customer_path(product_id, notifiable_id)
    end
  elsif action == "accepted"
    if notifiable_type == "Product" #team member invitation
      product_product_owner_panels_path(notifiable_id)
    elsif notifiable_type == "ProductCustomer" #referencer invitation
      product_customer = ProductCustomer.find(notifiable_id)
      product_id = product_customer.product_id
      product_product_owner_panels_path(product_id)
    end
  end
end