diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb new file mode 100644 index 000000000..512c64644 --- /dev/null +++ b/app/controllers/articles_controller.rb @@ -0,0 +1,107 @@ +class ArticlesController < ApplicationController + + # get / or /articles. + # Fetches articles based on search parameters and assigns them to an instance variable. + # + # @return [void] + def index + @articles = if params[:search] # search if search there's a search parameter + Article.search(params[:search]) + else + # return all articles + Article.all + end + end + + # get /articles/new. + # Assigns a new instance of Article to an instance variable. + # + # @return [void] + def new + @article = Article.new + end + + # post /articles. + # Creates a new article. + # + # @return [void] + def create + @article = Article.new(article_params) + + # redirect to article if saved successfully + if @article.save + redirect_to @article + else + # if there's an error return to new post page with unprocessable entity status + render :new, status: :unprocessable_entity + end + end + + # get /articles/:id. + # Fetches and assigns an article to an instance variable. + # + # @param :id [Integer] article ID + # + # @return [void] + def show + @article = Article.find(params[:id]) + end + + # get /articles/:id/edit. + # Fetches and assigns an article to an instance variable for editing. + # + # @param :id [Integer] The ID of the article to edit. + # + # @return [void] + def edit + @article = Article.find(params[:id]) + end + + # put or patch /articles/:id. + # Update an article. + # + # Updates an article with the specified ID using the given parameters. + # If the update is successful, redirects to the updated article. + # If the update fails, renders the edit template with an error status. + # + # @param :id [Integer] The ID of the article to update. + # @param :article_params [ActionController::Parameters] The parameters to update the article from form input. + # + # @return [void] + def update + @article = Article.find(params[:id]) + + # if update is completed, redirect + if @article.update(article_params) + redirect_to @article + else + # if there's a processing error, return to edit with unprocessable entity code. + render :edit, status: :unprocessable_entity + end + end + + # delete /articles/:id. + # Destroys an article and redirects to the root path. + # + # @param :id [Integer] ID of article to delete. + # + # @return [void] + def destroy + @article = Article.find(params[:id]) + @article.destroy + + redirect_to root_path, status: :see_other # redirect to root path with error code 303 + end + + private + + # Strong parameters method for filtering and permitting article parameters. + # + # @return [ActionController::Parameters] parameters object with the filtered and permitted parameters. + # + def article_params + # filters parameters based on type so data works with model + 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..9b0200630 --- /dev/null +++ b/app/models/article.rb @@ -0,0 +1,21 @@ +class Article < ApplicationRecord + before_validation :default_values # check if default values are required before validation + validates :title, :content, :author, :date, presence: true # require all fields + + # Sets author to 'Anonymous' if it is not already set + def default_values + unless self.author? + self.author = 'Anonymous' # set author to 'Anonymous' if not set + end + self.date ||= Date.today # if date is nil set to Date.today + end + + # Searches for articles that have a matching title or content. + # + # @param search [String] The search query. + # @return [ActiveRecord::Relation
] An ActiveRecord relation of articles that match the search query. + def self.search(search) + where("title LIKE ? or content LIKE ?", "%#{search}%", "%#{search}%") + end + +end diff --git a/app/views/articles/_form.html.erb b/app/views/articles/_form.html.erb new file mode 100644 index 000000000..a7a1c2d74 --- /dev/null +++ b/app/views/articles/_form.html.erb @@ -0,0 +1,31 @@ +<%= 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 %> +
+ +
+ <%= form.label :date %>
+ <%= form.text_field :date %> +
+ +
+ <%= form.submit %> +
+<% end %> diff --git a/app/views/articles/destroy.html.erb b/app/views/articles/destroy.html.erb new file mode 100644 index 000000000..02b852542 --- /dev/null +++ b/app/views/articles/destroy.html.erb @@ -0,0 +1,2 @@ +

Articles#destroy

+

Find me in app/views/articles/destroy.html.erb

diff --git a/app/views/articles/edit.html.erb b/app/views/articles/edit.html.erb new file mode 100644 index 000000000..8e3d8ff69 --- /dev/null +++ b/app/views/articles/edit.html.erb @@ -0,0 +1,2 @@ +

Edit <%= @article.title %>

+<%= 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..f6c887299 --- /dev/null +++ b/app/views/articles/index.html.erb @@ -0,0 +1,15 @@ +

Articles

+<%= form_with(url: articles_path, method: "get") do %> + <%= text_field_tag :search, params[:search] %> + <%= submit_tag "Search" %> +<% end %> + +<%= link_to "Create 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..024cdbe2c --- /dev/null +++ b/app/views/articles/new.html.erb @@ -0,0 +1,2 @@ +

New Article

+<%= render "form", article: @article %> \ 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..e5dc541cc --- /dev/null +++ b/app/views/articles/show.html.erb @@ -0,0 +1,10 @@ +

<%= @article.title %>

+

<%= @article.author %>

+

<%= @article.date %>

+

<%= @article.content %>

+ +<%= link_to "Edit", edit_article_path(@article) %>
+<%= link_to "Destroy", article_path(@article), data: { + turbo_method: :delete, + turbo_confirm: "Are you sure?" +} %> \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index a125ef085..45b861a76 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,10 +1,4 @@ Rails.application.routes.draw do - # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html - - # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. - # Can be used by load balancers and uptime monitors to verify that the app is live. - get "up" => "rails/health#show", as: :rails_health_check - - # Defines the root path route ("/") - # root "posts#index" + root "articles#index" # set root to direct to index method of articles_controller + resources :articles # sets up routes for articles automatically end diff --git a/db/migrate/20240129234034_create_articles.rb b/db/migrate/20240129234034_create_articles.rb new file mode 100644 index 000000000..f54e9966c --- /dev/null +++ b/db/migrate/20240129234034_create_articles.rb @@ -0,0 +1,12 @@ +class CreateArticles < ActiveRecord::Migration[7.1] + def change + create_table :articles do |t| + t.string :title + t.string :content + t.string :author + t.date :date + + t.timestamps + end + end +end diff --git a/db/migrate/20240129235228_change_content_to_text.rb b/db/migrate/20240129235228_change_content_to_text.rb new file mode 100644 index 000000000..d50685cfe --- /dev/null +++ b/db/migrate/20240129235228_change_content_to_text.rb @@ -0,0 +1,6 @@ +class ChangeContentToText < ActiveRecord::Migration[7.1] + def change + change_column :articles, + :content, :text + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 000000000..a8e37c8c1 --- /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_29_235228) 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/fixtures/articles.yml b/test/fixtures/articles.yml new file mode 100644 index 000000000..c807eea07 --- /dev/null +++ b/test/fixtures/articles.yml @@ -0,0 +1,13 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + title: MyString + content: MyString + author: MyString + date: 2024-01-29 + +two: + title: MyString + content: MyString + author: MyString + date: 2024-01-29 diff --git a/test/models/article_test.rb b/test/models/article_test.rb index 0d55b70ea..d880d78cd 100644 --- a/test/models/article_test.rb +++ b/test/models/article_test.rb @@ -1,6 +1,11 @@ require 'test_helper' class ArticleTest < ActiveSupport::TestCase + + setup do + Article.delete_all + end + test 'starts with no articles' do assert_equal 0, Article.count end