This is a simple survey tool built with Ruby on Rails. It allows users to create surveys with a single yes/no question, respond to surveys, and view the results of the surveys.
- Ruby 3.2
- Rails 7.1.2
- SQLite
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.
You need to have Ruby 3.2 and Rails 7.1.2 installed on your machine. You can check your version with:
ruby -v
rails -vIf you don't have Ruby and Rails installed, you can follow this guide.
A step by step series of examples that tell you how to get a development environment running.
- Clone the repo
- Install dependencies
bundle install- Database creation
rails db:create- Database initialization
rails db:migrate- Database seeding (optional)
rails db:seed- Run the Rails app
rails s- Navigate to
localhost:3000orlocalhost:3000/surveyson your browser. You should see the following
To run tests, run the following
RAILS_ENV=test bin/rails db:migrate
rails testAll tests should run and thus giving the following output
# Running:
...........
Finished in 0.621563s, 40.2212 runs/s, 122.2724 assertions/s.
25 runs, 76 assertions, 0 failures, 0 errors, 0 skips
demo.mov
Survey Tool has the following features
Please use Rails to build a simple survey tool, with the following requirements:
- A user should be able to create any number of surveys
- A survey consists of one question represented as a single string. The answer to the question is always Yes or No.
- The home screen of your app should show a list of surveys and a button to create a new one
- A user can respond to a survey by clicking into it from the list mentioned above
- A survey can be answered multiple times with a yes/no response
- You should keep track of when each of the survey responses are saved
- You should display the results of the survey on the home screen with the percentage of yes and no responses.
Creating a new `survey`
create_survey.mov
Responding to a `survey`
create_response.mov
Showing `responses` of a `survey`
show.mov
As the instructions for this assignment states
You don't need to worry about user authentication but you may stub this out if you wish
One solution is to use the Devise gem, a popular authentication solution for Rails. This will handle user registration, login/logout, password resets, and more.
The following section will contain details on how I would create my own user authentication.
We would create a users table that has a email: string and password_digest: string and password_confirmation: string
We would create a controller that handles displaying a registration form. We need endpoints for index, new, and create
Additionally, Rails has a has_secure_password method where we can handle password encryptions. We will use that and define that in the User model.
class UsersController < ApplicationController
skip_before_action :authenticate_user, only: [:new, :create]
def index
@users = User.all
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
flash[:notice] = "User created successfully"
redirect_to users_path
else
flash[:alert] = "User not created"
render :new, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name, :password)
end
endWe also need to manage the session so that we can keep track of the users that are logged-in. We need endpoints for new, create, and destroy
class UserSessionsController < ApplicationController
skip_before_action :authenticate_user, only: [:new, :create]
def new
@user = User.new
end
def create
@user = User.find_by(name: user_params[:name])
if @user && @user.authenticate(user_params[:password])
session[:user_id] = @user.id
redirect_to users_path
else
flash[:alert] = "Login failed"
redirect_to new_user_session_path
end
end
def destroy
session[:user_id] = nil
redirect_to root_path
end
private
def user_params
params.require(:user).permit(:name, :password)
end
endWe should only allow authenticated users to hit endpoints. To do this, we can define a AuthenticatedController or just simply do this in the ApplicationController. This controller will handle authenticating the user.
Here's a basic authentication function
def authenticate_user
unless current_user
render json: { message: 'Unauthorized' }, status: :unauthorized
end
end
def current_user
@current_user ||= User.find_by(id: session[:user_id])
endFor views, we can do the following instead
def authenticate_user
unless current_user
flash[:alert] = 'Unauthorized. Please log in'
redirect_to login_path
end
end
def current_user
@current_user ||= User.find_by(id: session[:user_id])
endFrom there, we can add it to each of the controllers! Essentially, we need this
append_before_action :authenticate_userWith the creation of the a new users table, we can add some new associations
- A
userhas many surveys, which means asurveybelongs to auser - A
userhas many responses to surveys, which means aresponsebelongs to auser
We can add some uniqueness validations throughout the app
- A
usercan only create asurveywith a unique name. - A
usercan only respond to asurveyonce
