Tagged: sql Toggle Comment Threads | Keyboard Shortcuts

  • kmitov 6:41 am on June 5, 2021 Permalink |
    Tags: , , , , sql   

    Yet another random failing spec 

    (Everyday Code – instead of keeping our knowledge in a README.md let’s share it with the internet)

    This article is about a random failing spec. I spent more than 5 hours on this trying to track it down so I decided to share with our team what has happened and what the stupid mistake was.

    Random failing

    Random failing specs are most of the time passing and sometimes failing. The context of their fail seems to be random.

    Context

    At FLLCasts.com we have categories. There was an error when people were visiting the categories. We receive each and every error on an email and some of the categories stopped working, because of a wrong sql query. After migration from Rails 6.0 to Rails 6.1 some of the queries started working differently mostly because of eager loads and we had to change them.

    The spec

    This is the code of the spec

     scenario "show category content" do
        category = FactoryBot.create(:category, slug: SecureRandom.hex(16))
        episode = FactoryBot.create(:episode, :published_with_thumbnail, title: SecureRandom.hex(16))
        material = FactoryBot.create(:material, :published_with_thumbnail, title: SecureRandom.hex(16))
        program = FactoryBot.create(:program, :published_with_thumbnail, title: SecureRandom.hex(16))
        course = FactoryBot.create(:course, :published_with_thumbnail, title: SecureRandom.hex(16))
    
        category.category_content_refs << FactoryBot.create(:category_content_ref, content: episode, category: category)
        category.category_content_refs << FactoryBot.create(:category_content_ref, content: material, category: category)
        category.category_content_refs << FactoryBot.create(:category_content_ref, content: program, category: category)
        category.category_content_refs << FactoryBot.create(:category_content_ref, content: course, category: category)
    
        expect(category.category_content_refs.count).to eq 4
        visit "/categories/#{category.to_param}"
    
        find_by_xpath_with_page_dump "//a[@href='/tutorials/#{episode.to_param}']"
        find_by_xpath_with_page_dump "//a[@href='/materials/#{material.to_param}']"
        find_by_xpath_with_page_dump "//a[@href='/programs/#{program.to_param}']"
        find_by_xpath_with_page_dump "//a[@href='/courses/#{course.to_param}']"
    
      end

    We add a few objects tot he category and then we check that we see them when we visit the category.

    The problem

    Sometime while running the spec only 1 of the objects in the category are shown. Sometimes non, most of the time all of them are shown.

    The debug process

    The controller

    def show
      @category_content_refs ||= @category.category_content_refs.published
    end

    In the category we just call published to get all the published content that is in this category. There are other things in the show but they are not relevant. We were using apply_scopes, we were using other concerns.

    The model

      scope :published, lambda {
        include_contents.where(PUBLISHED_OR_COMING_WHERE_SQL)
      }

    The scope in the model makes a query for published or coming.

    And the query, i kid you not, that was committed in 2018 and we’ve had this query for so long was

    class CategoryContentRef < ApplicationRecord
       
        PUBLISHED_OR_COMING_WHERE_SQL = ' (category_content_refs.content_type = \'Episode\' AND (episodes.published_at <= ? OR episodes.is_visible = true) ) OR
         (category_content_refs.content_type = \'Course\' AND courses.published_at <= ?) OR
         (category_content_refs.content_type = \'Material\' AND (materials.published_at <= ? OR materials.is_visible = true) ) OR
         category_content_refs.content_type=\'Playlist\'', *[Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")]*4].freeze
    
    end
    

    I will give you a hit that the problem is with this query.

    You can take a moment a try to see where the problem is.

    The query problem

    The problem is with the .freeze and the constant in the class. The query is initialized when the class is loaded. Because of this it takes the time at the moment of loading the class and not the time of the query.

    Because the specs are fast sometimes the time of loading of the class is right before the spec and sometimes there are specs executed in between.

    It seems simple once you see it, but these are the kind of things that you keep missing while debugging. They are right in-front of your eyes and yet again sometimes you just can’t see them, until you finally see them and they you can not unsee them.

     
  • kmitov 7:36 pm on February 15, 2021 Permalink |
    Tags: , , , sql   

    Usage of ActiveRecord::Relation#missing/associated 

    Today I learned that Rails 6.1 adds query method associated to check for the association presence. Good to know. I share it with the team at Axlessoft along with the community as a whole.

    While reading the article about the methods I thought:

    Are we going to use these methods in our code base?

    I did some greps and it turns out we won’t.

    $ git grep -A 10 joins | grep where.not | grep nil | wc -l
    0
    

    There is not a single place in our code that we call

    .joins(:association).where.not(association: {id: nil}
    
    or
    
    .joins(:association).where(association: {id: nil})

    What does this mean?

    Nothing actually. Great methods. I was just curious to see if we will be using them in our code base a lot.

     
  • kmitov 5:30 pm on January 27, 2021 Permalink |
    Tags: , , sql   

    What is the most complex query that you are comfortable to live with before refactoring? 

    (Everyday Code – instead of keeping our knowledge in a README.md let’s share it with the internet)

    Today I did some refactoring and I again worked with a query that I kind of never got to refactor and it is the most “complex” query that we seem to be comfortable with in our platforms because other queries are improved, but this one stays the same. This does not mean that it is not understandable or not maintainable, it is just the most “complex” we seem to be comfortable with, because any more complex than this and we naturally think about refactoring it.

    This got me thinking.

    What are other real life examples for the most complex relation database queries others are comfortable enough to live with before thinking about changing the model or the scheme.

    Is my threshold too low or too high?

    I would be happy to learn more from you.

    Here is the query (Active Record) in question:

    Get all the references for 'Tasks' that are in CourseSections that are in Courses
    and filter all of them through the translations they have
    
    These are 8 tables (ContentRef, Task, CourseSection, Course, and 4 translation tables)

    # Get all the references for 'Tasks' that are in CourseSections that are in Courses 
    # and filter all of them through the translations they have
    # 
    # These are 8 tables (ContentRef, Task, CourseSection, Course, and 4 translation tables) 
    ContentRef.
      joins(:course_section). 
      includes(:translations).
      includes(:task)
      includes(task:[:translations]).
      includes(course_section: [course: [:translations]]).
      includes(course_section:[:translations]).
      where(courses:{id: course_ids }, content_type: "Task").
      select("content_refs.*, course_translations.*, course_section_translations.*, task_translations.*")
    
    # The models is
    Content Ref 
      belongs_to CourseSection
      belongs_to Task
      has_many :translations
    
    CourseSection
      belongs_to Course
      has_many :translations
    
    Course 
      has_many :translation
    
    Task 
      has_many :translation
    
     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel