ruby on rails tips and tricks for developers

Ruby On Rails Developers: Tips And Tricks

Ruby On Rails Developers: Tips And Tricks

#1) Don't Overthink The Controller

Rails are built on the MVC architecture. It is important to maintain a thin controller to increase the readability and testing of code.

You can use the index method to extract a list of red and yellow shirts.

"{class ShirtsController < ApplicationController

def index

@white_shirts = Shirt.where(color: 'White')

@red_shirts = Shirt.where(colour: 'Red')

end}"

Now, transferring this code to the database called "Shirt model" to extract the red and white, we hope you can see how much simpler it is to construct the controller's index method.

This will help to specify these searches even more precisely.

"{class Shirt < ActiveRecord::Base

scope :color, -> (option){ where(color: option) }

end

class ShirtsController < ApplicationController

def index

@white_shirts = Shirt.color('white')

@red_shirts = Shirt.color('red')

end}"

When you encounter Database queries in the controller method, always use the second approach. There are many ways to use logic, but we recommend using the following best practices in the controller.

  • Logical handling of cookies and sessions.
  • Logic to find the correct model for DB operations.
  • The logic to render the result is based on request types like HTML, XML or JSON Or redirecting.
  • Use logic to collect parameters and perform operations according to your requirements.

#2) Avoid Putting Too Much Logic Into Your View

ERB allows you to embed ruby within HTML. You need to be careful when building your views. Large-view files can be difficult to maintain and manage.

It is possible to get into code repetition in this area, which can lead to DRY (don't duplicate yourself) violations.

Some recommended best practices of Rails:

  • Use helpers whenever possible.
  • Use layouts and partials when you find that the same code is repeated in multiple views.
  • Use presenters/decorators like the Draper gem, which will greatly help you reduce the code in your view files.

#3) Models Should Not Be Overly Logical

Active Record models are not responsible for all functionality. For example, generating email notifications and interacting with external services.

Active Record's core functionality is to perform CRUD in a database.

The model has some very powerful logic:

  • Active Record relations(Associations) and validations.
  • Simple methods that will update attributes in a database and save them.
  • The full_name method, which combines the first_name and last_name fields in the database, is an example of how Access Wrappers can conceal core model information.
  • Avoid using Active Record queries that are not database related.

We have literally been saying we don't use logic anywhere in MVC. You may stop and think about where we can use our logic.

Did they say no to logic anywhere on the rails? Evidently not! You can use logic inside MVC, but it is not recommended. Instead, you can use all logic outside of MVC, which won't affect the performance of your application and is also easy to manage with responsible programmer Ruby on rails.

#4) Do Not Use Too Many Gems

Remember that the gems you add to your Rails application can have dependencies. Gems, in turn, may depend on other gems.

Rails applications that have more gems will be larger than they need to be. This can slow down application performance. It may also lead to increased server memory configurations and higher operating costs.

Did you know that by adding the gem "rails_admin" to your application, 11 additional gems will be added? These 11 additional gems could have more dependent gems, and so on.

Always be sure to cross-check and double-check when adding gems to your application.

#5) Always Check Your Logs

It is important to keep an eye on your log files during the testing and development of your application. You will run into N+1 query problems often.

Reviewing your log files is the only way to find out what the problem is. It is easy to identify inefficiencies by reviewing log files.

#6) Automated Tests Are Always Better Than Manual Ones

At least one high-level test case should be written for every action in your controller. This testing development framework can be used to verify the basic functionality of an application if it is ever extended, modified, or upgraded into a new ROR version.

By writing test cases, you may find defects in your logic.

#7) Background Tasks

We have been integrating third-party services in our applications using gems that call their APIs. But we can't guarantee it will run smoothly.

What if the service becomes very slow? You can avoid blocking calls by making them background tasks instead of calling the services directly as a request.

These are the most popular gemstones for this purpose:

  • Delayed job
  • Sidekiq
  • Resque

#8) Use Haml or Slim Templating Language For Your Views

Rails default to the ERB Templating System, allowing you to embed Ruby code within HTML. Always use Slim or HAML templates if possible, as they are lighter than ERB.

The syntax of Slim or HAML is much easier than ERB. Slim is a lightweight, fast-templating engine. This will help you to achieve cleaner code, greater readability and reduced response times.

This also makes it possible to create your front end quickly.

#9) Useful Gems for Organizing Your Code and Increasing your App's Performance

Bullet - A powerful gem that increases the performance of your application. It displays an alert message in your browser when identifying N+1 query problems.

Rails Best Practices - It provides suggestions and checks the code quality.

Deadweight - It identifies CSS selectors that are not used.

#10) Some Practical Ruby On Rails Advice

  • Database Indexing: Indexing the database is one of the easiest ways to improve performance.

    This will speed up the retrieval of data from the database.

  • Views: Do not call DB queries directly from your views.

    This will have a significant impact on the performance of your app.

  • Controller Variables: All dynamic data you use in your views must be defined using the controller variables.
  • SAAS: Always in SAAS, write your styles (CSS) to prevent style overrides.
  • Content Tag: Do not use content_tag when calling
  • Helpers: Instead, call them partials.

    Rails create, by default, a helper for each controller.

    Use aspect-oriented helpers such as form helper and links helper.

Discover our Unique Services - A Game Changer for Your Business!

Tips For Building Rails Applications

Tips For Building Rails Applications

#1. N+1 Queries Can Be Eliminated By Using Includes, eager_load

This is something that every experienced Rails developer knows or find ruby on rails developers, but it's still worth mentioning.

Used to query a list that spans multiple tables. Product. Map product.brand.name, for example, gets a list with brand names that would generate SQL statements equal to the number of products in the database.

Simply modify it to Product to avoid this. Rails would eagerly load the list of brands first if you included (: brand) in your code. Although the initial query is heavier, you should avoid using multiple SQL statements if you can get the information you need simultaneously.

You can use the bullet gem to find these nasty optimization leaks. We highly recommend using this gem to detect these issues early in any Rails project.

#2. Batch Inserts And Updates

As with the previous tip, avoid looping multiple SQL statements to create and update records. We had a case where we needed to insert or modify thousands of records each minute, and looping was painful.

Rails 6 now supports bulk inserts using three methods: Insert_all and Insert_all, Upsert_all. You can use the ActiveRecord import gem if you are using an older Rails version.

#3. Learn The Differences Between Common Ruby Methods

It is important to know the differences between the most common Ruby methods, even though they will not make or break the application in most cases.

Rails are constantly changing its behavior, which causes confusion among Rails developers. Rails 5.1 has stabilized the situation.

Present vs Exists and Any

  • Present? If not loaded already, load all records and check if at least one is present.
  • It is very slow when the recording is still being loaded.
  • Produces a Select "*".
  • Exists? will always query to see if there is at least one entry in the database.
  • It is fastest when only checking for the existence of the record is required, but it can be slower if you already have the record loaded.
  • Produces SELECT1 LIMIT 1.
  • Any?Produces SELECT Count(*) for Rails 4.2 and Select 1 Limit 1 for Rails 5.1.1 and higher.
  • It is present if the records have already been loaded.
  • It is loaded if records are not.
  • In Rails 5.0 or below, is it still slower than .exists? Any generates the same query for Rails 5.1 or higher as .exists?.

Rule Of Thumb

  • Use Exists to check for the existence of a document.
  • Use present if the record has already been loaded or if you will use the results.
  • In Rails 4.2 or below, it is rarely used.

    It can be used if you know when to use it.? For newer Rails versions, and is recommended.

Blank? Empty?

  • Blank?
    • Is negation present?
    • is present, so the same rule applies.
  • Empty?
    • Is it the same as?
    • Produces SELECT Count(*) for Rails 4.2 and Select 1 Limit 1 for Rails 5 and higher.

Rule Of Thumb

  • Using Rails 4.2 or below, can you negate the Exists? to test for existence.

    .empty? is available for newer versions.

  • Is it the same as? can only be used if a record has already been loaded.

Count vs Size vs Length

  • length
    • It is similar in that it loads the association if not already loaded.
  • count
    • This will always produce a SQL query.

      Has a similar behavior?

  • size
    • If the array has already been loaded, Like any? Behaves as long as possible.

      It will use a COUNT if the array is already loaded.

Rule Of Thumb

  • size is usually recommended.
  • Use length if the record has already been loaded in memory or if you want to load an association into memory.

Note: Because size and duration always generate SQL queries, the results may not be identical. It's best to double-check!

#4. Tuning Your Puma Configuration Requires Time

Puma is Rails' default web server. Puma is configured to run on a single worker and use threads for multiple requests.

Puma can be tuned to run in clustered modes with multiple threads and workers. Do some load testing in a production environment to find the optimal number of threads and workers.

While this is a great starting point, it should not be a rule. You can increase the number of CPU cores to four or five times and still see a significant performance gain.

However, this would increase your CPU or RAM, so be sure to check it out during load testing. Rails apps are notorious for consuming a lot of memory, so be sure not to run out of that to hire dedicated ruby on rails developer.

No one-size-fits-all solution exists, but you should aim for at least three workers per container or server with 3 to five threads.

Consider moving to a stronger instance or dyno if you cannot have 3 workers due to CPU or memory limitations. Listen to Nate Berkopec's great talk on tuning your web server configuration. Consider also checking out Puma v5's experimental features! We had great success in using the wait_for_less_busy_worker and the nakoyoshi_fork for programmer productivity.

#5. Use A Fast JSON Serializer

We would stay away from using the still popular active_model_serializer gem. Use the fast_json_api (originally developed by Netflix) serializer or something similar.

Use the oj jewel, which provides faster json handling. This can be a big help when processing large quantities of JSON programmer productivity.

#6. Use a CDN Before Your Load Balancer

If you are using AWS, point your Route53 record at a CloudFront Distribution in front of your Application Load Balancing (ALB).

Cloudfront will then optimize traffic to your application to go through the closest edge location of code within the AWS global networks. An edge location of code is likely much closer to the end user than the ALB. You may experience different results, but ours improved 80-100ms in latency by simply pointing Cloudfront to the ALB.

Note that we have not implemented any sort of caching essential components in the programming language.

Be sure to customize Cloudfront to point at your application's errors page before doing this. Cloudfront's error page should not be ugly.

You don't want your customers to see it. You can also configure AWS WAF to protect your app from malicious attacks on the programming ruby.

#7. Use HTTP Caching

You can cache your http data through the CDN once you've configured a CDN to be in front of ALB. It will be very fast since all data is cached on the edge.

This is not an easy setup. There are many factors to take into consideration. You can cause yourself headaches by accidentally catching the wrong items.

It can be rewarding, but proceed cautiously.

#8. Use Redis To Cache Fragments

Rails cache files by default. This isn't the best option if you're running a production website with multiple web servers, each with its own cache stores.

Rails now support caching using Redis. Redis caches the data in memory, which makes any app load much faster. Your site can serve thousands of users without purchasing additional CPU or memory.

Consider using the hired Gem to load Redis cached content faster. ElastiCache can also be used in production to ease the management of your Redis cluster.

#9. Use Soft Deletes

We would advise you to avoid hard deletions. Hard deletes remove the row completely from the database and are final.

You cannot "undo" anything unless you have backups. In general terms, it would be useful to know when records have been deleted. The popular "discard gem" adds an elegant way to soft deletes.

#10. Use Pagy to paginate

Pagy consumes more memory than other popular pager gems like Kaminari or will_paginate. Pagy, the new kid in town, is more efficient.

#11. Use jemmaloc or set MALLOC_ARENA_MAX=2

Set MALLOC_ARENA_MAX=2, and see if your app's memory consumption improves. We were surprised at how this relatively small change reduced our app's memory footprint by around 10%.

Try running ruby with jemmaloc to reduce memory usage. We have not personally used jemmaloc to run Ruby, but several articles recommend it.

#12. When Possible, Use The Database

SQL is a fundamental part of Rails development. ActiveRecord is a simple abstraction over SQL. ActiveRecord is a better alternative to Ruby's .map and .select.

SQL is designed to filter and query data, so it's faster and more efficient. Use the right tool to do the job.

# Bad orders.select order.state == pending # Good orders.where (state: pending)

For complex queries, you may have no choice but to use raw SQL by using ActiveRecord.connection.execute(sql_string).

ActiveRecord is still the best option, even though raw SQL will be faster. Maintaining long lines of SQL can become unbearable over time. Use raw SQL only when ActiveRecord prevents you from completing the task.

#13. Be Cautious With Rails Migrations

When adding indexes, always add a code>disable_ddl_transaction!/code> along with code>algorithm: concurrently/code> to prevent any unexpected downtimes when deploying to production.

Also, when adding indexes, always add a disable_ddl_transaction! Together with the algorithm: concurrently prevent any unexpected downtimes when deploying to production. The topic is long, so check out the guidelines for the strong_migrations jewel. We don't normally put the gem into my app, but it is helpful to learn about the general guidelines to achieve zero-downtime migrations.

#14. Learn Your Indexes

You should always index your foreign keys. The lol_dba jewel can be used to determine if indexes are missing. Be familiar with index types other than B-Tree.

We have primarily used Postgres, but we think it would be similar to other SQL engines. Here's a quick walkthrough:

Indexes With Multiple Columns:

  • This can be much faster than using a single index, so it is worth considering.

    Postgres is able to combine two indexes, so performance can vary.

  • The order of the index is important.

    The Postgres documentation states:

Suppose your workload is a mixture of queries involving columns x and y and sometimes only the x column. In that case, you may create separate indexes for x and y and use index combinations to process queries involving both columns.

You can also create a multicolumn (x,y) index. This index is more efficient for queries involving both columns but would be useless for queries including y. It should not be your only index.

Combining the multicolumn and a separate index for y could be a good solution. The multicolumn could be used for queries that only involve x. However, it would be slower and larger than an index containing x.

Partial Indexes:

  • A with clause.
  • Useful for enforcing a partial constraint that is unique.
  • Let's use an example: Say you want to limit the number of active orders a user can have.

    You can enforce only one order per user by using a partial unique index if you need to.

  • This type of index can also be useful for accessing a table with a condition that would result in the filtered records being significantly smaller.
    • For example, you have a table of orders with the states pending and complete.

      Orders with a completed state will increase over time as orders are marked complete daily.

      Our app's queries are more likely to be interested in pending orders.

      A partial index is beneficial because there's a large difference between thousands of pending and millions of completed orders.

GIN Index:

  • Often is used to speed up Like queries.

    While we recommend against using your database for full-text search queries, a GIN Index can be extremely helpful in certain situations.

#15. Default Values, Unique/Null Constraints And Default Values

Consider the default values for your database columns. Should it be nil? Should it be 0 or code>nil/code>? null is different from zero or an empty string.

It's probably best to specify the default value and a Not Null constraint if it does not matter. You'll save yourself some headaches in the future.

When dealing with booleans, it is best to specify a default and a not NULL constraint. No one would want three possible values in a Boolean column: true-false, and null programming experience.

#16. Search With ElasticSearch to Find What You Need

ElasticSearch makes it easy to create a powerful search engine ready for production. You can manage Elasticsearch's quirks and syntax using the elasticsearch_rails jewel in conjunction with search kick.

This is another tool that you will need to manage, so it's only worth considering if your search needs are complex. Although it isn't difficult to install, this adds another layer of complexity to the app. If you want to minimize the maintenance burden, consider using a managed service such as AWS ElasticSearch for programming ruby.

You can use the popular gem ransack for a simpler search. Use this gem only for simple searches, as it relies on the database.

When you use the LIKE operators, be careful. One time, we confused the _eq predicate with _matches and wondered why our queries ran so slowly in programming ruby.

#17. Consider Using Count Estimates

Use Postgres count estimations when you don't need a precise count. The count estimation query is fast and usually accurate enough.

#18. Use EXPLAIN and ANALYZE to Make Sense Of Your Queries

Use EXPLAIN and ANALYZE to understand how your query executes its actions. Unfortunately, ActiveRecord does not have native support, but you can opt to use the ActiveRecord-explain-analyze gem.

EXPLAIN and ANALYZE results can be difficult to understand when you have complex queries. This handy tool from Depesz will help you make sense of explained statements.

#19. Run A Few Queries To Get Database Insights

You can use SQL queries to get a better idea of the state of your database. Look at the rails_pg_extras Gem for different SQL commands.

You can run a few rake tasks to get a better understanding of index_usage, outliers and locks.

#20. Reduce Table/Index Bloat With pg_repack

Have you been using a database for many years? Do you feel that queries are getting significantly slower? Does it happen with a table that has frequent updates and deletions? Check if you have bloated tables or indexes by running rake: bloat in the rails_pg_extras jewel.

When we perform thousands of updates and deletes in our database, the bloat increases. Postgres doesn't delete the row but marks it as unavailable for all future transactions.

We are simplifying this, but the row is still on disk. It's just not visible. This would increase over time for large databases. This is the bloat that slows down your queries.

VACUUM FULL will completely remove the bloat. This command will lock your table with EXCLUSIVE LOCKS, meaning that no reading or writing can be done during the command.

Yikes. This would result in downtime for any production environment. Install pg_repack instead, which will allow you to eliminate all bloatware without having an exclusive lock.

Get a Free Estimation or Talk to Our Business Manager!

Wrapping Up

It's over! Congratulations on reaching the end of this list in a blog post. We are certain that there are things we have not covered, but there will never be a complete list.

Please let us know if you've got any other tips! Don't be overwhelmed if you are just beginning your web development journey! You'll get there if you take things one step at a time or hire ruby on rails developers from coders.dev.

Paul
Full Stack Developer

Paul is a highly skilled Full Stack Developer with a solid educational background that includes a Bachelor's degree in Computer Science and a Master's degree in Software Engineering, as well as a decade of hands-on experience. Certifications such as AWS Certified Solutions Architect, and Agile Scrum Master bolster his knowledge. Paul's excellent contributions to the software development industry have garnered him a slew of prizes and accolades, cementing his status as a top-tier professional. Aside from coding, he finds relief in her interests, which include hiking through beautiful landscapes, finding creative outlets through painting, and giving back to the community by participating in local tech education programmer.

Related articles