diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 29d07fe5e..cd032554a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 3.2.3 + ruby-version: 3.3.0 bundler-cache: true - name: Run tests diff --git a/.gitignore b/.gitignore index 5fb66c9f0..c41a2d39a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ # Ignore master key for decrypting credentials and more. /config/master.key +.DS_Store diff --git a/.ruby-version b/.ruby-version index b347b11ea..15a279981 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.2.3 +3.3.0 diff --git a/Gemfile b/Gemfile index 7abd44d7a..28697d2a0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" -ruby "3.2.3" +ruby "3.3.0" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" gem "rails", "~> 7.1.2" diff --git a/Gemfile.lock b/Gemfile.lock index ac898c77c..b897baea6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -238,7 +238,7 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webdrivers (5.3.1) + webdrivers (5.3.0) nokogiri (~> 1.6) rubyzip (>= 1.3.0) selenium-webdriver (~> 4.0, < 4.11) @@ -276,7 +276,7 @@ DEPENDENCIES webdrivers RUBY VERSION - ruby 3.2.3p157 + ruby 3.3.0p0 BUNDLED WITH 2.5.5 diff --git a/README.md b/README.md index 29c5b607c..cf0941d23 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,27 @@ -# Technical Instructions -1. Fork this repo to your local Github account. -2. Create a new branch to complete all your work in. -3. Test your work using the provided tests -4. Create a Pull Request against the Shopify Main branch when you're done and all tests are passing +# Shopify Engineering Internships Backend Technical Challenge +This is a Ruby on Rails Application created for Shopify's Engineering Internship Program 2024. # Project Overview -The Rails application you will be working on is an Encyclopedia, which allows users to create, view, edit, and delete articles. The application also provides search functionality to help users find relevant articles. Be sure to implement basic CRUD actions on articles. Your task is to implement these features as well as write the code that makes the tests pass. - -# Project Goals -The main goal of this internship project is to implement the functionality required to make the existing tests pass. The provided tests cover various aspects of the application, including creating and viewing articles, editing and updating articles, deleting articles, and searching for articles. Along with completing the tests, be sure to implement all basic CRUD actions on your articles on a controller and create views to see your work in the app. - -## Your specific goals for this project are as follows: - -1. Review Existing Tests: Start by reviewing the existing tests provided in the article_test.rb file located in the test/models directory. Understand the requirements and expectations of each test. - -2. Implement Functionality: Write the code necessary to make the existing tests pass. This involves implementing the required actions and logic in the models, controllers, and views to fulfill the specified requirements. Also be sure to implement basic CRUD actions and demonstrate proper MVC principals. - -3. Ensure Code Quality: Write clean, well-structured, and maintainable code. Follow best practices and adhere to the Ruby on Rails conventions. Pay attention to code readability, modularity, and performance. - -4. Test Your Code: After implementing the functionality, run the tests to ensure that they pass successfully. Fix any failures or errors that occur and retest until all tests pass. - -5. Code Documentation: Document your code by adding comments and explanatory notes where necessary. This will help other developers understand your implementation and make future maintenance easier. - -6. Version Control: Use Git for version control. Commit your changes regularly and push them to a branch in your forked repository. - -7. Create a Pull Request: Once you have completed the project goals, create a pull request to merge your changes into the main repository. Provide a clear description of the changes made and any relevant information for the code review. +The Rails application is an implementation of an Encyclopedia, which allows users to create, view, edit, and delete articles. The application also provides search functionality to help users find relevant articles. ## Getting Started To get started with this project, follow these steps: 1. Clone the repository to your local development environment. - -2. Install the necessary dependencies by running bundle install in the project directory. - -3. Familiarize yourself with the existing codebase, including the models, controllers, and views. - -4. Review the existing tests in the article_test.rb file and understand their purpose and functionality. - -5. Run the tests locally to ensure they are passing. - -6. Start working on the goals outlined above, making improvements to the existing tests and adding new tests as needed. - -7. Commit your changes regularly and push them to a branch in your forked repository. - -8. Once you have completed the project goals, create a pull request to merge your changes into the main repository. - -## Resources -Here are some resources that may be helpful during your internship project: - -- [Ruby on Rails Guides](https://guides.rubyonrails.org/) - Comprehensive guides on Ruby on Rails, covering various aspects of web application development. - -- [Ruby Style Guide](https://rubystyle.guide/) - A community-driven Ruby coding style guide to ensure consistent and readable code. - -- [Git Documentation](https://git-scm.com/doc) - Official documentation for Git, the version control system used in this project. +2. You will need to install Ruby and SQLite3 +3. Install the necessary dependencies by running bundle install in the project directory. +``` +bundle install +``` +3. Run the server in the application directory in the terminal + +``` +bin/rails server +``` +4. Go to localhost:3000 to view the app + +5. To run the test suite + +``` +bin/rails test +``` diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb new file mode 100644 index 000000000..56c248cce --- /dev/null +++ b/app/controllers/articles_controller.rb @@ -0,0 +1,62 @@ +class ArticlesController < ApplicationController + + def index + @articles = Article.all + end + + # searches for an article + def search + @articles = if params[:q] + Article.search(params[:q]) + end + end + + # show a single article + def show + @article = Article.find(params[:id]) + end + + # create a new article + def new + @article = Article.new + end + + # post a new article + def create + @article = Article.new(article_params) + + if @article.save + redirect_to @article + else + render :new, status: :unprocessable_entity + end + end + + def edit + @article = Article.find(params[:id]) + end + + # updates existing article + def update + @article = Article.find(params[:id]) + + if @article.update(article_params) + redirect_to @article + else + render :edit, status: :unprocessable_entity + end + end + + # destroys an article + def destroy + @article = Article.find(params[:id]) + @article.destroy + + redirect_to root_path, status: :see_other + end + + private + def article_params + params.require(:article).permit(:title, :content, :author, :date) + end +end diff --git a/app/helpers/articles_helper.rb b/app/helpers/articles_helper.rb new file mode 100644 index 000000000..296827759 --- /dev/null +++ b/app/helpers/articles_helper.rb @@ -0,0 +1,2 @@ +module ArticlesHelper +end diff --git a/app/models/article.rb b/app/models/article.rb new file mode 100644 index 000000000..da361fcf7 --- /dev/null +++ b/app/models/article.rb @@ -0,0 +1,12 @@ +class Article < ApplicationRecord + validates :title, presence: true, length: {minimum: 1 } + validates :content, presence: true, length: { minimum: 10 } + validates :author, presence: false + validates :date, presence: false + + + def self.search(q) + return Article.where("title LIKE ? OR content LIKE ? OR author LIKE ?", + "%" + q + "%", "%" + q + "%", "%" + q + "%") + end +end diff --git a/app/views/articles/_form.html.erb b/app/views/articles/_form.html.erb new file mode 100644 index 000000000..a8bb14bd5 --- /dev/null +++ b/app/views/articles/_form.html.erb @@ -0,0 +1,38 @@ +<%= form_with model: article do |form| %> +
+ <%= form.label :title %>
+ <%= form.text_field :title %> + <% article.errors.full_messages_for(:title).each do |message| %> +
<%= message %>
+ <% end %> +
+ +
+ <%= form.label :content %>
+ <%= form.text_area :content %>
+ <% article.errors.full_messages_for(:content).each do |message| %> +
<%= message %>
+ <% end %> +
+ +
+ <%= form.label :author %>
+ <%= form.text_field :author %> + <% article.errors.full_messages_for(:author).each do |message| %> +
<%= message %>
+ <% end %> +
+ +
+ <%= form.label :date %>
+ <%= form.date_select :date %> + <% article.errors.full_messages_for(:date).each do |message| %> +
<%= message %>
+ <% end %> +
+ +
+
+ <%= form.submit %> +
+<% end %> \ No newline at end of file diff --git a/app/views/articles/edit.html.erb b/app/views/articles/edit.html.erb new file mode 100644 index 000000000..e5ca19800 --- /dev/null +++ b/app/views/articles/edit.html.erb @@ -0,0 +1,3 @@ +

Edit Article

+ +<%= render "form", article: @article %> \ No newline at end of file diff --git a/app/views/articles/index.html.erb b/app/views/articles/index.html.erb new file mode 100644 index 000000000..7b3e4e8e6 --- /dev/null +++ b/app/views/articles/index.html.erb @@ -0,0 +1,11 @@ +

Articles

+ + + +<%= link_to "New Article", new_article_path %> \ No newline at end of file diff --git a/app/views/articles/new.html.erb b/app/views/articles/new.html.erb new file mode 100644 index 000000000..1daeb7f04 --- /dev/null +++ b/app/views/articles/new.html.erb @@ -0,0 +1,3 @@ +

New Article

+ +<%= render "form", article: @article %> \ No newline at end of file diff --git a/app/views/articles/search.html.erb b/app/views/articles/search.html.erb new file mode 100644 index 000000000..acb53c445 --- /dev/null +++ b/app/views/articles/search.html.erb @@ -0,0 +1,11 @@ +

Search Results

+ +<% if @articles.present? %> + +<% else %> +

No articles found. Please try another search.

+<% end %> \ No newline at end of file diff --git a/app/views/articles/show.html.erb b/app/views/articles/show.html.erb new file mode 100644 index 000000000..2d88f3267 --- /dev/null +++ b/app/views/articles/show.html.erb @@ -0,0 +1,16 @@ +

<%= @article.title %>

+ +

<%= @article.content %>

+ +

By: <%= @article.author %>

+ +

<%= @article.date %>

+ + \ No newline at end of file diff --git a/app/views/home/_navbar.html.erb b/app/views/home/_navbar.html.erb new file mode 100644 index 000000000..dd3886661 --- /dev/null +++ b/app/views/home/_navbar.html.erb @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 812bfb90f..e66cdacc3 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,16 +1,22 @@ - - + + - EngInternAssessmentRails - + + + Encyclopedia App + <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> - + <%= render 'home/navbar'%> +
+
<%= yield %> +
+ - + \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index a125ef085..9bed56086 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,5 +6,11 @@ get "up" => "rails/health#show", as: :rails_health_check # Defines the root path route ("/") - # root "posts#index" + root "articles#index" + + # route for search + get "search", to:"articles#search" + + # resourceful routing - maps all conventional routes for Articles + resources :articles end diff --git a/db/migrate/20240128005115_create_articles.rb b/db/migrate/20240128005115_create_articles.rb new file mode 100644 index 000000000..84add4e46 --- /dev/null +++ b/db/migrate/20240128005115_create_articles.rb @@ -0,0 +1,12 @@ +class CreateArticles < ActiveRecord::Migration[7.1] + def change + create_table :articles do |t| + t.string :title + t.text :content + t.string :author + t.date :date + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 000000000..0577feeb0 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,23 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.1].define(version: 2024_01_28_005115) do + create_table "articles", force: :cascade do |t| + t.string "title" + t.text "content" + t.string "author" + t.date "date" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + +end diff --git a/test/controllers/articles_controller_test.rb b/test/controllers/articles_controller_test.rb new file mode 100644 index 000000000..0a82cbb19 --- /dev/null +++ b/test/controllers/articles_controller_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ArticlesControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end diff --git a/test/models/article_test.rb b/test/models/article_test.rb index 0d55b70ea..3c7ce04fc 100644 --- a/test/models/article_test.rb +++ b/test/models/article_test.rb @@ -44,6 +44,14 @@ class ArticleTest < ActiveSupport::TestCase assert_equal 0, Article.count end + test 'deletes specified articles in a table containing > 1 article' do + article1 = Article.create(title: 'Sample Article', content: 'Lorem ipsum dolor sit amet.') + article2 = Article.create(title: 'Hello Article', content: 'Lorem ipsum dolor sit amet.') + article3 = Article.create(title: 'Bye Article', content: 'ipsum dolor sit amet.') + article1.destroy + assert_equal 2, Article.count + end + test 'prevents access to deleted articles' do article = Article.create(title: 'Sample Article', content: 'Lorem ipsum dolor sit amet.') article.destroy @@ -65,4 +73,12 @@ class ArticleTest < ActiveSupport::TestCase assert_includes results, article2 assert_not_includes results, article1 end + + test 'article not created if title and/or content are null' do + article1 = Article.create() + article2 = Article.create(title: "Sample Article") + article3 = Article.create(content: "Hello World! This is amazing!") + assert_equal 0, Article.count + end + end