Ruby/Rails Flashcards
Explain the difference between Active Record and Action Pack in Rails?
In essence, while Active Record focuses on the data layer, allowing seamless interaction between the application and its database, Action Pack deals with the web request-response cycle, managing controllers, views, and routing. It consists of Action Controller and Action View.
Explain Active Record
Active Record is the Object-Relational Mapping (ORM) layer for Rails. It provides the interface and functionality to connect Ruby objects with database tables. This allows Rails developers to interact with the database using object-oriented methods without writing raw SQL queries.
What are the key features of Active Record?
- Model Representation: Each table in the database corresponds to a Ruby class in the application. Rows in the table are represented as objects of the class. The columns correspond to the attributes of the objects.
- CRUD Operations: Active Record gives methods to create, read, update, and delete records in the database without manually writing SQL.
- Associations: Active Record makes it easier to create relations between models (e.g., has_many, belongs_to).
- Validations: Before saving to the database, Active Record can validate the data to ensure it meets certain criteria.
- Query Interface: Active Record provides a rich API for querying the database and chaining conditions, which translates to SQL queries behind the scenes.
What are the key features of Action Pack?
- Action Controller: Manages the controller aspect of the MVC framework. It processes incoming HTTP requests, handles user input, session management, and routes the request to appropriate actions and views.
- Action View: Manages views of the MVC framework. It’s responsible for rendering the HTML or other output formats in response to the user’s request. Embedded Ruby (ERB) is often used within Action View templates to embed Ruby code within HTML.
- Routing: Works in tandem with Action Controller to decode the incoming HTTP requests’ URLs and dispatch them to the correct controller’s action method.
- Helpers: Provides utility methods that can be used in views to render HTML content.
- Asset Pipeline: Supports the inclusion and management of application assets like JavaScript, CSS, and images.
What are Models?
- Purpose: Represents the data structure, business logic, and the rules of the application. A model corresponds to a table in the database.
Key Responsibilities: - Data Interaction: Handles interactions with the database. You can create, read, update, and delete records in the database using models without writing raw SQL.
- Validations: Ensures that the data being saved to the database meets predefined criteria.
- Associations: Defines the relationships between models (e.g., has_many, belongs_to, has_one, has_and_belongs_to_many).
- Business Logic: Encapsulates the core functions that the application can perform on the data, like calculations or transformations.
What are Views?
- Purpose: Presents data to the user in a readable format. It’s the user interface of the application.
Key Responsibilities: - Data Presentation: Displays the data to the user. For instance, when you see a list of blog posts on a website, that’s typically the work of a view.
- Template Rendering: Uses Embedded Ruby (ERB) to embed Ruby code within HTML templates, allowing dynamic content generation based on the data provided by controllers.
- Helpers: Utilizes view helpers to streamline the rendering process. Helpers are methods that can be used in views to perform common tasks, like generating links or forms.
What are Controllers?
- Purpose: Acts as an intermediary between models and views. It processes incoming requests, interacts with models to get or manipulate data, and then sends that data to the view to be displayed.
Key Responsibilities: - Request Handling: Processes incoming HTTP requests (like GET, POST) and routes them to the appropriate action method.
- Data Processing: After fetching or manipulating data via models, the controller prepares it for the view.
- Response Management: Determines which view to display and sends the final rendered view back to the client’s browser.
- Session Management: Maintains data that should persist across requests, like the info of a logged-in user.
Describe a typical Rails application flow.
- The user sends a request from their browser, which hits the Rails router.
- The router directs the request to the appropriate controller’s action.
- The controller might interact with one or multiple models to fetch or manipulate data.
- The controller sends the necessary data to a view.
- The view renders the data and sends the resulting HTML back through the controller and to the user’s browser.
This separation in MVC ensures a clear distinction between different responsibilities, leading to organized and maintainable code.
How would you set up a one-to-many relationship between two models using Active Record?
Database Setup: Ensure that the child model’s table (the “many” side) has a foreign key column referring to the parent model. For instance, if we’re associating User and Post, the posts table should have a user_id column.
Model Association: In the parent model (e.g., User), you’d use the has_many method to denote the relationship:
class User < ApplicationRecord
has_many :posts
end
In the child model (e.g., Post), you’d use the belongs_to method:
class Post < ApplicationRecord
belongs_to :user
end
Using the Relationship: Once set up, you can fetch associated records easily. For instance, for a given user, user.posts would fetch all their posts, and for a given post, post.user would fetch its associated user.
Caveats and Good Practices: It’s worth noting the option to add the dependent: :destroy on the has_many side. This means if the parent record is destroyed, all associated child records are also destroyed. Also, for data integrity, it’s often a good idea to add validations to ensure every child record has an associated parent.
What is RESTful routing, and how is it implemented in Rails?
In the context of Rails, RESTful routing ensures that controllers and their actions are organized around CRUD operations (Create, Read, Update, Delete) for a particular resource.
Routes are organized around resources, typically corresponding to models in your application. For instance, if you have a Book model, your routes will be set up to handle operations on books.
What are the Standardized Routes and HTTP Verbs?
Rails’ RESTful routes use a combination of standard HTTP verbs and URLs to represent CRUD actions:
- Create: POST /books
- Read: GET /books/:id
- Update: PATCH/PUT /books/:id
- Delete: DELETE /books/:id
* And so on for other actions, including listing all books (GET /books) and presenting a form to create a new book (GET /books/new).
With the resources method in the routes.rb file, Rails provides a way to generate standard RESTful routes for a given resource with a single line of code:
resources :books
* This generates all the standard CRUD routes for books.
What tools or gems do you use for testing in Rails?
RSpec: testing framework for Rails applications. It’s expressive and integrates seamlessly with Rails, allowing for highly readable tests.
FactoryBot: For creating test data, I use the FactoryBot gem. It lets me set up test objects with default attributes and provides a clean and DRY approach to initializing test data.
Capybara: For feature or integration tests, Capybara is my go-to. It simulates how a user interacts with the app and tests the entire stack, including JavaScript behavior when used with drivers like Selenium or WebKit.
DatabaseCleaner: It ensures a clean slate for tests by cleaning up the test database between each run, ensuring data residue doesn’t interfere with other tests.
Shoulda Matchers: It provides RSpec-compatible one-liners that test common Rails functionalities, like validations and associations, making tests concise and easy to read.
SimpleCov: To ensure I have good test coverage across my application, I use SimpleCov. It provides a visual report of lines of code that haven’t been executed during test runs.
Can you describe your testing approach or strategy for a Rails application?
Model Tests: I begin by writing unit tests for models, ensuring that validations, associations, and any custom logic are correctly functioning. This provides a solid foundation and ensures data integrity.
Controller Tests: Here, I focus on testing various outcomes based on received parameters and user roles, ensuring not just that actions work, but that they also provide the right HTTP responses, render the expected views, or redirect as anticipated.
Feature/Integration Tests: These are crucial for testing user flows end-to-end. From logging in, performing actions, to logging out, I simulate real user behaviors to make sure the entire user experience works seamlessly.
TDD/BDD: Whenever possible, I adopt a Test-Driven Development (TDD) or Behavior-Driven Development (BDD) approach, writing tests first, then the application code. This not only ensures everything is testable from the start but also helps in designing the architecture.
Continuous Integration (CI): Implementing CI tools like Jenkins or GitHub Actions to run tests automatically for every pull request ensures that new code integrations don’t introduce regressions.
Regular Code Reviews: Beyond automated testing, I believe in the value of regular code reviews. They provide a chance for team members to spot potential issues and discuss better approaches.
What strategies would you use to identify and resolve performance bottlenecks in a Rails application?
Profiling: Before diving into solutions, it’s crucial to identify where the bottlenecks are. Profiling your application helps you understand which parts of the codebase are consuming the most resources.
Log Analysis: Rails logs provide a wealth of information. Regularly examining them can give insights into slow database queries, excessive rendering times, and other inefficiencies.
Benchmarking: Measure the performance of specific code sections or actions both before and after making optimizations to quantify improvements.
Database Optimization: Slow database queries are often culprits. By examining the SQL being executed, you can optimize queries, add necessary indexes, and denormalize tables if required.
Caching: Introduce caching mechanisms at various levels - page caching, action caching, fragment caching, or low-level caching using something like Redis or Memcached.
Frontend Performance: Sometimes, bottlenecks are on the client side. This might involve optimizing asset delivery, reducing the number of requests, or improving JavaScript performance.
Regular Code Reviews: Encourage the team to review each other’s code. Another pair of eyes can often spot inefficient algorithms or suboptimal queries
What is CSRF? How does Rails protect against it?
CSRF stands for Cross-Site Request Forgery. This is a form of an attack where the attacker submits a form on your behalf to a different website, potentially causing damage or revealing sensitive information
In order to protect against CSRF attacks, you can add protect_from_forgery to your ApplicationController. This will then cause Rails to require a CSRF token to be present before accepting any POST, PUT, or DELETE requests.
Attackers are prevented from stealing the CSRF token by browsers’ “same origin” policy.