Setting up a form on Ruby on Rails where there is only an email to submit on a homepage without using the Devise gem
As per Rails and REST convention you shouldn't put the form in home.html.erb instead do the following,
In your users controller add new method and your controller will look like below,
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
redirect_to 'pages/success'
else
redirect_to 'pages/error'
end
end
private
def user_params
params.require(:user).permit(:email)
end
end
Now move your form to new.html.erb
in users folder like below,
<%= form_for @user, url: users_path do |f| %>
<div class="wrapper">
<%= f.text_field :email , id: "search", class:"search input" %> <br />
<%= f.submit "yep", class: "submit input" %>
</div>
<% end %>
And don't forget to add routes,
root "users#new"
Also, model user.rb should have uniqueness validation
validates_uniqueness_of :email
form_for - Ruby on Rails
A little explanation ( form_for
documentation here):
<%= form_for @user, :as => :user, :url => sign_in_path(@user) do |f| %>
Point 1. :as => :user
This is the name used to generate the input's name (and the params' names), example:
= form_for Admin.new, as: :user do |f|
#^^^^
= f.input :username
# will generate an input like this:
<input type='text' name='user[username]' #... />
#^^^^
Point 2. :url => sign_in_path(@user)
In the tutorial, @user
is set like this:
def sign_in
@user = User.new
end
Point 3. @user
available in other actions
You have to set this variable in each action you want it. It can be redundant, so you can use a before_filter in order to authenticate set the @user
variable at each action your want:
class UsersController < ApplicationController
before_filter :set_user_variable
def set_user_variable
@user ||= User.find(session[:user_id]) if session[:user_id].present?
end
end
If you want to make it available everywhere in your app (implies that you must be connected to a user account to browse the app):
class ApplicationController < ActionController::Base
before_filter :set_user_variable, except: [:sign_in, :login]
def set_user_variable
@user ||= User.find(session[:user_id]) if session[:user_id].present?
end
Point 4. form_for (User.new)
We set the variable @user
in the controller and pass it as an argument to form_for
because it is a Rails Convention to never call a Model's name directly in the views, and it is deprecated to provoke SQL queries in the view.
Example:
######## WRONG
# view
<%= Post.find(params[:id]).title %>
######## MUCH BETTER
# controller's action:
def show
@post = Post.find(params[:id])
# view
<%= @post.title %>
Instance Variables set in the Action of a Controller are shared between the actions, its view and its partial views.
Point 5. do/end block in form_for
Please give your input at this point, not sure how to explain it
This part of the code is called a do/end block, it represents a piece of code that will be executed in the context of the form_for
. We use the form_for
's instance as the variable defined in the pipes, here it is |f|
. I usually don't use |f|
, it is not really relevant to me. I prefer to use this kind of variable name:
= form_for @user do |user_form_builder|
= user_form_builder.input :username
Which I think is more readable and easier to understand.
how form_for works in Ruby on Rails
I didnt do that tutorial so mind me if i dont answer directly to your question.
Take a look at the rails guide about form helpers and it explains in details your questions, probably in a more articulate way than i can.
form_for(path/to/your/controller/action)
is a helper method to create HTML form elements with the url path to the POST or GET request. The helper knows if it should be a new record or an update record based on what you are asking to do in your controller action.
For example
In your controller
def new
@my_instance_variable = Myobject.new
end
In your view new.html.erb
<%= form_for @my_instance_variable do |f| %>
...
<% end %>
In your case the logic was directly written in the helper and you could also directly write
<%= form_for Myobject.new %>
Both will result with the following html
<form action="/myobjects/new" method="post">
# in this case rails knows its a `POST` request because the route new action
# is by default a POST request. You can check these routes and their request
# by using `rake routes` in terminal.
Then the hidden_field
is another helper to contain a value, in your case the @user.id
that will be passed as parameter then saved as a Create or update action for the given object. The reason it doesnt add the value in the hidden field tag is because you already have a model association that knows the id of user since the link of form uses the build method with user id.
Last part you need to understand the form_for link logic
current_user.relationships
# implies the association of the current_user has many relationships
current_user.relationships.build
# .build is a method to populate a new object that can be save as a new record
# means you will create a new relationship record by populating the user_id
# column with the current_user.id and the followed_id with the target @user.id
Ruby on Rails form input
The HTML is generated by the Rails form helpers. Rails gives you a bunch of methods to make it easier to generate form markup so you don't have to worry about naming and typing out all of the attributes every time. Checkout that link to the docs to get more familiar.
How render form with previously entered data when validation fails
You are never setting the input's values. I'd suggest you use rails' form helpers like form_for
and the rest. https://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object
<%= form_for @user do |f| %>
<%= label :username %>
<%= text_field :username %>
<%= label :email %>
<%= text_field :email %>
<%= label :password %>
<%= password_field :password %>
<%= submit %>
<% end %>
EDIT: there's even a section on the tutorial you linked that tells you to use form_for :S
Related Topics
What Are the Main Differences Between Sinatra and Ramaze
Generate Ruby Classes from Xsd
Installing Gem Fails with Permissions Error
Rails Activeadmin: Showing Table of a Related Resource in the Same View
Loop Through Activerecord::Associations::Collectionproxy with Each
Context Aware Authorization Using Cancan
Best Way to Monitor for Completion of a Sidekiq Job
Gem Dependencies Versions Meaning
How to Add a Method to the Global Scope in Ruby
Heroku Gem Not Working with Rvm
Declaring Instance Variables Iterating Over a Hash!
How to Validate Associated Model Id
Getting a Dns Txt Record in Ruby
How to Check If a Folder Exists in Chef
Rails 5.2.0 with Ruby 2.5.1 Console - 'Warning:' 'Already' Initialized Constant Fileutils::Version
Error About Nokogiri While Capistrano Deployment on Ubuntu Server