I need to create a campaign with given prizes. My models already are related and accepting nested attributes.
View:
<%= form_for #campaign, remote: true do |f| %>
<% 5.times do |i| %>
<%= f.fields_for :prizes do |prize_form| %>
<div class="form-group">
<%= prize_form.label "prize #{i + 1}" %>
<%= prize_form.text_field :name %>
</div>
<% end %>
<% end %>
<% end %>
Which generates:
<input id="campaign_prizes_attributes_0_name" name="campaign[prizes_attributes][0][name]" type="text">
<input id="campaign_prizes_attributes_1_name" name="campaign[prizes_attributes][1][name]" type="text">
<input id="campaign_prizes_attributes_2_name" name="campaign[prizes_attributes][2][name]" type="text">
<input id="campaign_prizes_attributes_3_name" name="campaign[prizes_attributes][3][name]" type="text">
<input id="campaign_prizes_attributes_4_name" name="campaign[prizes_attributes][4][name]" type="text">
In my controller I have this
class CampaignsController < ApplicationController
respond_to :html, :js
def index
#campaigns = Campaign.all
end
def new
#campaign = Campaign.new
#campaign.prizes.build
end
def create
#campaign = Campaign.new(campaign_params)
#campaign.prizes.build
end
def campaign_params
params.require(:campaign).permit(:name, :date_start, :date_end, :status, :rules, prizes_attributes: [name: []])
end
end
No matter what I do, I always get this error:
Unpermitted parameters: name
I need to make each campaign have a varying ammount of prizes, but I'm not able to make this work. What am I doing wrong?
Thanks.
The campaign_params method should be:
def campaign_params
params.require(:campaign).permit(:name,
:date_start,
:date_end,
:status,
:rules,
prizes_attributes: [ :name ])
end
How permit nested attributes
Your campaign_params are wrong
prizes_attributes: [name: []]
must be
prizes_attributes: [:name]
Related
I have a project with a search feature. I have three classes, Product, Review and User. I have a self.search method in the product model doing a query on all three class tables.
When I put together the search view, It listed the product name, the review author and any text in a review that matches the search string.
Then I thought, lets pretty that up a bit.
So I'm cross referencing the ids to also list user avatars and time stamps and star ratings. But to do that, I'm making local variables searching in all the classes.
So I think there's now quite a code smell here. There is no controller to load up with #users = User.all. I'm sticking with _user = User.find_by types of local variable assignment. The search fingers are now in all class pies.
So my question is really, should my bloated search now rightly to be scaffolded into an actual class? Or is there another approach like a helper? Is it possible this is not that bad of an approach?
Ruby 2.6.5
Rails 5.2.4
Here is my view:
<div class="home-container">
<div class="welcome-sub-header">
<h1>Search Results</h1>
<div class='search-flex-container'>
<h2>Products that Match</h2>
<% if #results_products.empty?%>
<div class='search-noresult-card'>
<p>No products matched the search.</p>
</div>
<% end %>
<% #results_products.each do |results_product| %>
<div class='search-product-card'>
<div class='search-product-flex'>
<%= render partial: "shared/product_image", locals: { product: results_product } %>
<%= link_to results_product.name, product_path(results_product.id) %>
<p>Imported From <%= results_product.country %></p>
<div class="search-adjust-stars">
<%= render partial: "shared/review_stars", locals: { review: results_product.average_review } %>
</div>
</div>
</div>
<% end %>
<%= will_paginate #results_products %>
<h2>Product Reviews that Match</h2>
<% if #results_reviewers.empty?%>
<div class='search-noresult-card'>
<p>No reviewers matched the search.</p>
</div>
<% end %>
<% #results_reviewers.each do |results_reviewer| %>
<div class='search-review-card'>
<div class='search-review-flex'>
<% _reviewed_product = Product.find_by(id: results_reviewer.product_id) %>
<% _user = User.find_by(id: results_reviewer.user_id) %>
<div class="search-review-box1">
<%= render partial: "shared/avatar", locals: { user: _user } %>
<%= link_to (results_reviewer.author + " review of " + _reviewed_product.name), review_path(id: results_reviewer, product_id: results_reviewer.product_id) %><br>
</div>
<div class="search-review-box2">
<%= render partial: "shared/review_stars", locals: { review: results_reviewer.rating } %>
</div>
<div class="search-review-box3">
<p>On <%= results_reviewer.created_at.strftime('%m-%d-%Y') %></p>
</div>
<div class="search-review-box5">
<%= render partial: "shared/product_image", locals: { product: _reviewed_product } %>
</div>
</div>
</div>
<% end %>
<%= will_paginate #results_reviewers %>
<h2>Review Text that Matches</h2>
<% if #results_reviews.empty?%>
<div class='search-noresult-card'>
<p>No review text matched the search.</p>
</div>
<% end %>
<% #results_reviews.each do |results_review| %>
<% _user = User.find_by(id: results_review.user_id) %>
<div class='search-review-card'>
<%= render partial: "shared/avatar", locals: { user: _user } %>
<% _reviewed_product = Product.find_by(id: results_review.product_id) %>
<%= link_to (results_review.author + " review of " + _reviewed_product.name), review_path(id: results_review, product_id: results_review.product_id) %>
<p>Reviewed on <%= results_review.created_at.strftime('%m-%d-%Y') %></p>
<div class="search-review-text">
<%= results_review.content_body %>
</div>
</div>
<% end %>
<%= will_paginate #results_reviews %>
</div>
</div>
<div>Font made from oNline Web Fontsis licensed by CC BY 3.0</div>
</div>
This is the Product model with the self.search method.
class Product < ApplicationRecord
has_many :reviews, dependent: :destroy
validates :name, presence: true
validates_length_of :name, maximum: 30
validates :price, presence: true
validates_length_of :price, maximum: 8
validates :country, presence: true
validates_length_of :country, maximum: 50
has_one_attached :product_photo
before_save(:titleize_product)
scope :most_reviewed, -> {(
select("products.id, products.name, products.average_review,products.price, products.country, count(reviews.id) as reviews_count")
.joins(:reviews)
.group("products.id")
.order("reviews_count DESC")
.limit(6)
)}
scope :newest_product, -> { order(created_at: :desc).limit(6) }
scope :highest_reviewed, -> {(
select("products.id, products.name, products.price, products.country, products.average_review as average_review")
.joins(:reviews)
.group("products.id")
.order("average_review DESC")
.limit(6)
)}
def self.search(search)
where("lower(reviews.author) LIKE :search OR lower(products.name) LIKE :search OR lower(reviews.content_body) LIKE :search", search: "%#{search.downcase}%").uniq
end
def next
Product.where("id > ?", id).order("id ASC").first || Product.first
end
def previous
Product.where("id < ?", id).order("id DESC").first || Product.last
end
private
def titleize_product
self.name = self.name.titleize
self.country = self.country.titleize
end
end
I think you should separate search method into searchable module, and allow searchable-models declare what attributes involve in search query.
module Searchable
extend ActiveSupport::Concern
included do
#search_clauses ||= Hash.new
end
module ClassMethods
def search(key_search, scope: 'default')
search_clause ||= search_string_for(scope)
relation = joins(*search_clause[:joins].map(&:to_sym)) unless search_clause[:joins].blank?
(relation || self).where(search_clause[:where], key: "%#{key_search.downcase}%")
end
def search_clause(clause_str, scope: 'default')
#search_clauses[scope] = parse(clause_str)
# we can add dynamic function like seach_`scope_name`
end
def search_attributes(attributes, scope: 'default')
search_clause(attributes.map { |attribute| "%#{attribute}%"}.join(" OR "), scope: scope)
end
private
def search_string_for(scope)
#search_clauses&.dig(scope)
end
def parse(clause)
join_tables = Set.new
where_clause = clause.dup
parse_tables(clause) do |table|
join_tables << table unless table == self.class_name.tableize || table.blank?
where_clause.sub!("#{table}.", "#{table.tableize}.")
end
parse_logics!(where_clause)
parse_matches!(where_clause)
# other cases ...
{
joins: join_tables,
where: where_clause
}
end
def parse_logics!(clause)
clause.gsub!(/\|/, "OR")
clause.gsub!(/\&/, "AND")
# other ...
end
def parse_matches!(clause)
clause.scan(/(?<=%)[^\s\|\&\z\Z]*(?=%)/).each do |attribute|
clause.sub!(/%[^\s\|\&\z\Z]*%/, "lower(#{attribute}) LIKE :key")
end
end
def parse_tables(clause, &block)
clause.scan(/(?<=[%\s])[^%\s\|\&\z]*(?=\.)/).each(&block)
end
end
end
Example in my practice project:
class Task < ApplicationRecord
include Searchable
belongs_to :requirement
has_many :skills
# declare search clause, we can set the whole where-clause here
# those syntax %,|,& ... just for fun (simple way)
search_clause "%content% | %requirement.description%"
# with scope
search_clause "(%content% | %requirement.description%) & status = 0", scope: :open
# declare attributes
search_attributes %w[content skills.name], scope: :skill
end
# Demo
Task.search("setup") # default scope
Task.search("setup", scope: :open)
Task.search("ruby", scope: :skill)
Note: I recommend you use search-gems such as ransack, pg_search (in case of full-text-search).
I'm trying to allocate an address a custom id so it's not easy to guess the record (for people who want to add and change other people's addresses). For some reason, whilst I can create a record with the correct path being created, the edit path from form_with seems to be not using the custom resource param.
routes.rb
resources :deladdresses, param: :delid
_form.html.erb
<%= form_with model: deladdress, class: "mt-4" do |f| %>
<%= render "shared/error_messages", resource: f.object %>
.. lots removed for clarity ...
<%= f.hidden_field :country, value: "Australia" %>
<%= f.hidden_field :ordernum, name: :ordernum, value: #order %>
<%= link_to order_path(#order.ordernum) do %>
<button class="btn btn-secondary">Back</button>
<% end %>
<%= f.button "Save", id: 'submit', class: "btn btn-primary" %>
<% end %>
Which is coming from in my new.html.erb and edit.html.erb:
<%= render "form", deladdress: #deladdress %>
deladdress.rb
class Deladdress < ApplicationRecord
before_save :add_del_id
belongs_to :user
has_many :orders
def add_del_id
randchars = ("a".."z").to_a.sample(8).join
time = DateTime.now.strftime("%H%M%S")
self.delid = "#{time}-#{randchars.upcase}"
end
end
deladdress_controller.rb
class DeladdressesController < ApplicationController
before_action :find_my_order
def show
# Collect the delivery address for the order
# Do we want to collect and store these per customer?
end
def new
if current_user
#savedaddresses = Deladdress.where(user: current_user)
end
#deladdress = Deladdress.new
end
def edit
#deladdress = Deladdress.where(delid: params[:delid]).first
end
def create
#deladdress = Deladdress.create(deladdress_params)
#deladdress.user = current_user
if #deladdress
#order&.update(deladdress: #deladdress)
redirect_to order_path(#order.ordernum), notice: "Address added"
else
render :new
end
end
def update
#deladdress = Deladdress.where(delid: params[:delid]).first
if #deladdress.update(deladdress_params)
#order.update(deladdress: #deladdress)
redirect_to order_path(#order.ordernum), notice: t(".updated")
else
render :edit
end
end
private
def deladdress_params
attributes = [:first_name, :last_name, :address, :apartment, :city, :state, :country, :postcode, :ordernum, :delid]
params.require(:deladdress).permit(*attributes)
end
def find_my_order
#order = find_order
end
end
When I go to the following url http://localhost:5000/deladdresses/112750-UBTYOJGK/edit, I can see the delid is there. But, when I look at the form which it is going to try and submit I have the following. The id is 5 and not 112750-UBTYOJGK.
<form class="mt-4" action="/deladdresses/5" accept-charset="UTF-8" data-remote="true" method="post">
<input type="hidden" name="_method" value="patch">
<input type="hidden" name="authenticity_token" value="XXXXXXXXXXXX">
<button name="button" type="submit" id="submit" class="btn btn-primary">Save</button>
</form>
I am obviously missing something but I really don't know what.
Thanks in advance for any help you might be able to give to have this work.
You can pass the url for the form to the form helper like so:
for where you call the edit form:
<%= render "form", deladdress: #deladdress, url: deladress_path(#deladress.delid) %>
for where you call the new form:
<%= render "form", deladdress: #deladdress, url: deladresses_path %>
and then in the form itself:
<%= form_with model: deladdress, url: url, class: "mt-4" do |f| %>
...
I am building a simple form with Ruby on Rails to submit an order.
My form needs to submit information from 3 different models: the user, the catalog_item and the order itself.
Here's my order model:
class Order < ApplicationRecord
after_initialize :default_values
validates :quantity, presence: true
belongs_to :user
belongs_to :catalog_item
validates :user_id, presence: true
validates :catalog_item_id, presence: true
accepts_nested_attributes_for :user
validates_associated :user
end
Here's my user model:
class User < ApplicationRecord
has_many :orders
end
Here's my controller:
class OrdersController < ApplicationController
def checkout
#order = Order.new(catalog_item: CatalogItem.find(params[:catalog_item_id]), user: User.new)
end
def create
#order = Order.new(order_params)
if #order.save
# redirect_to confirmation_path
else
# redirect_to error_path
end
end
private
def user_params
[:name, :email, :phone_number]
end
def order_params
params.require(:order).permit(:id, :catalog_item_id, user_attributes: user_params)
end
end
And here is my view form:
<%= form_for #order do |order_form| %>
<%= order_form.hidden_field :catalog_item_id %>
<%= order_form.fields_for :user do |user_fields| %>
<%= user_fields.label :name %>
<%= user_fields.text_field :name %>
<%= user_fields.label :email %>
<%= user_fields.text_field :email %>
<%= user_fields.label :phone_number %>
<%= user_fields.text_field :phone_number %>
<% end %>
<%= order_form.submit %>
<% end %>
This if the form HTML:
<form class="new_order" id="new_order" action="/orders" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓"><input type="hidden" name="authenticity_token" value="+z8JfieTzJrNgsr99C4jwBtXqIrpNtiEGPdVi73qJrpiGPpjYzbLwUng+e+yp8nIS/TLODWVFQtZqS/45SUoJQ==">
<input type="hidden" value="1" name="order[catalog_item_id]" id="order_catalog_item_id">
<label for="order_user_attributes_name">Name</label>
<input type="text" name="order[user_attributes][name]" id="order_user_attributes_name">
<label for="order_user_attributes_email">Email</label>
<input type="text" name="order[user_attributes][email]" id="order_user_attributes_email">
<label for="order_user_attributes_phone_number">Phone number</label>
<input type="text" name="order[user_attributes][phone_number]" id="order_user_attributes_phone_number">
<input type="submit" name="commit" value="Create Order" data-disable-with="Create Order">
Here are my routes:
get 'checkout/:catalog_item_id', to: 'orders#checkout', as: 'checkout'
post 'orders', to: 'orders#create'
When I try to save the #order inside the action create I get this error:
#<ActiveModel::Errors:0x007fe95d58b698 #base=#<Order id: nil, quantity: 1, created_at: nil, updated_at: nil, user_id: nil, catalog_item_id: 1>, #messages={:user_id=>["can't be blank"]}, #details={:user_id=>[{:error=>:blank}]}>
However it does work if I do this:
#catalog_item = CatalogItem.find(order_params[:catalog_item_id])
#user = User.new(order_params[:user_attributes])
#user.save
#order = Order.new(catalog_item: #catalog_item, user: #user)
This is what is being sent in the HTTP request when I post the form:
order[catalog_item_id]:1
order[user_attributes][name]:Ana
order[user_attributes][email]:ana#gmail.com
order[user_attributes][phone_number]:123123123
commit:Create Order
I am new to RoR and I don't understand why order_params doesn't have the user but it does have the catalog_item_id.
Any help will be truly appreciated. Thank you!
Assuming that your Order model belongs_to :user, My "suggested-rails-best-practice" solution is as follows:
See Rails Nested Attributes for more info. Basically what Nested Attributes does is it allows you to "create" also an associated record (in your example, the associated User) in just one command:
# example code:
Order.create(
catalog_item_id: 1,
user_attributes: {
name: 'Foo',
email: 'foo#bar.com'
}
)
# above will create two records (i.e.):
# 1) <Order id: 1 catalog_item_id: 1>
# 2) <User id: 1, order_id: 1, name: 'Foo', email: 'foo#bar.com'>
Now that you can also pass in user_attributes as part of the hash when creating an order, it's easy enough to just treat user_attributes as also part of the request params, see controller below.
Model:
# app/models/order.rb
belongs_to :user
accepts_nested_attributes_for :user
# from our discussion, the validation needs to be updated into:
validates :user, presence: true
validates :category_item, presence: true
Controller:
# app/controllers/orders_controller.rb
def create
#order = Order.new(order_params)
if #order.save
# DO SOMETHING WHEN SAVED SUCCESSFULLY
else
# DO SOMETHING WHEN SAVING FAILED (i.e. when validation errors)
render :checkout
end
end
private
# "Rails Strong Params" see for more info: http://api.rubyonrails.org/classes/ActionController/StrongParameters.html
def order_params
params.require(:order).permit(:id, :catalog_item_id, user_attributes: [:name, :email, :phone_number])
end
View;
<%= form_for #order do |order_form| %>
<!-- YOU NEED TO PASS IN catalog_item_id as a hidden field so that when the form is submitted the :catalog_item_id having the value pre-set on your `checkout` action, will be also submitted as part of the request -->
<%= order_form.hidden_field :catalog_item_id %>
<%= order_form.fields_for :user do |user_form| %>
<%= user_form.label :name %>
<%= user_form.text_field :name %>
<%= user_form.label :email %>
<%= user_form.text_field :email %>
<%= user_form.label :phone_number %>
<%= user_form.text_field :phone_number %>
<% end %>
<%= order_form.submit %>
<% end %>
User is a class so fields_for :user creates fields for a new user object.
Try calling order_form.fields_for instead of fields_for to scope the fields_for to your order object.
If you want the user to be able to create orders from the show view for an item you can setup a nested route instead:
resources :catalog_items do
resources :orders, only: [:create]
end
Make sure you have
class Order < ApplicationRecord
belongs_to :user
belongs_to :catalog_item_id
accepts_nested_attributes_for :user
validates_associated :user # triggers user validations
end
class CatalogItem
has_many :orders
end
Then you can do:
# /app/views/orders/_form.html.erb
<%= form_for [#catalog_item, #order || #catalog_item.orders.new] do |order_form| %>
<%= order_form.fields_for :user do |user_fields| %>
<%= user_fields.label :name %>
<%= user_fields.text_field :name %>
<%= user_fields.label :email %>
<%= user_fields.text_field :email %>
<%= user_fields.label :phone_number %>
<%= user_fields.text_field :phone_number %>
<% end %>
<%= order_form.submit %>
<% end %>
# /app/views/catalog_items/show
<%= render partial: 'orders/form' %>
This will set the form url to /catalog_items/:catalog_item_id/orders. which means that we pass catalog_item_id through the URL and not the form params -
- this is a better practice as it makes the route descriptive and RESTful.
Then setup the controller:
class OrderController
# POST /catalog_items/:catalog_item_id/orders
def create
#catalog_item = CatalogItem.find(params[:catalog_item_id])
#order = #catalog_item.orders.new(order_params)
# Uncomment the next line if you have some sort of authentication like Devise
# #order.user = current_user if user_signed_in?
if #order.save
redirect_to #catalog_item, success: 'Thank you for your order'
else
render 'catalog_items/show' # render show view with errors.
end
end
# ...
private
def user_params
[:name, :email, :phone_number]
end
def order_params
params.require(:order)
.permit(:id, user_attributes: user_params)
end
end
I am having problem sending values to my controller via a form_tag-- It looks like the params are missing, I get this error: ActionController::ParameterMissing: param is missing or the value is empty: story
<% #locations.each do |post| %>
<div class="box col3">
<img src="<%= post[:image] %>">
<small>username: </small><%= post[:username]%>
<small>posted date: </small><%= post[:created_time] %>
<small>place: </small><%= post[:place] %>
<small>tags: </small> <%= post[:hash_tags] %>
<small>lat: </small> <%= post[:lat] %>
<small>lg: </small> <%= post[:lg] %>
<div class="like-button">
<%= form_tag('/stories/create', remote: true) do %>
<%= hidden_field_tag 'avatar', "#{post[:image]}" %>
<%= hidden_field_tag 'description', "#{post[:username]}" %>
<%= submit_tag "Like", class: "btn btn-warning like-button" %>
<% end %>
</div>
</div>
<%end%>
#locations is an array of hashes.
for example #locations.first yield:
{:lat=>40.7519798,
:lg=>-73.9475174,
:place=>"Z Hotel NY",
:profile_picture=>
"http://photos-g.ak.instagram.com/hphotos-ak-xtp1/t51.2885-19/s150x150/12105211_896812917070398_1478405438_a.jpg",
:hash_tags=>[],
:username=>"dannessex90",
:fullname=>"Dann Essex",
:created_time=>"2015-11-02 22:41:25 -0500",
:image=>
"https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s320x320/e35/11421986_972505559476106_241708523_n.jpg"}
story controller:
class StoriesController < ApplicationController
def index
#stories = Story.all
end
def show
end
def new
#story = Story.new
end
def edit
end
def create
current_location = request.remote_ip
binding.pry
coordinates = Location.get_coord(story_params[:location])
params = {description: story_params[:description], location: story_params[:location], latitude: coordinates[0], longitude: coordinates[1], avatar: story_params[:avatar]}
#story = current_user.stories.build(params)
if #story.save
redirect_to url_for(:controller => :users, :action => :my_stories)
else
render 'searches/result'
end
end
private
def story_params
params.require(:story).permit(:description, :location, :avatar, :tag_list)
end
end
Any idea what is going wrong?
This is happening because you have specified to require story in your parameters through strong_params i.e. in your story_params method.
The view side is not passing the parameters nested under story param. That's why you are getting this error.
To solve this issue, you can change your story_params method to this (without the require(:story) part, because you are not using it in your controller):
def story_params
params.permit(:description, :location, :avatar, :tag_list)
end
I am trying to send some data from view to controller. I am using form. I have one manufacturer controller and one user controller. What I want to do whenever I am creating new manufacturer I am also creating new user with certain values.So my form contains few values for manufacturer and few for user. I tried these things in following ways:
// inside ManufacturersController
def new
#manufacturer = Manufacturer.new
#user = User.new
end
def create
#manufacturer = Manufacturer.new(manufacturer_params)
#user = User.new(user_params)
#manufacturer.save
redirect_to #manufacturer
end
private
def manufacturer_params
params.permit(:name, :license_no, :contact_no, :address, :country, :city, :pincode,:email_id)
end
def user_params
params.permit(:email, :password, :confirm_password)
end
// inside form view
<div class="form-group">
<label class="col-sm-3 control-label">Email Id</label>
<div class="col-sm-3">
<input class="form-control" name="email_id" value="<%= #manufacturer.email_id %>">
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Password</label>
<div class="col-sm-6">
<input class="form-control" name="password" value="<%= #user.password %>">
</div>
Above code is not completed code. I getting error at my form field password. It shows error undefined method password for #<User:0x7a42580>
Am I doing anything wrong? Need some help. Thank you.
In Rails you pass the params for a resource in a hash:
user: { name: 'Max' }
That how the built in form helpers work and it's a good practice.
When creating forms you can use the form helpers to get the correct html name attribute for your inputs.
<%= form_for(#user) do %>
<%= f.text_field :email # user[name] %>
<%= f.password_field :password # user[password] %>
<% end %>
Rails will bind the value of #user.email to the email field.
When you want to create multiple records at once you can use accepts_nested_attributes_for:
class Manufacturer < ActiveRecord::Base
has_many :users
accepts_nested_attributes_for :users
validates_associatiated :users
end
class User < ActiveRecord::Base
belongs_to :manufacturer
end
this lets you do Manufacturer.new(name: 'Acme Corp', users_attibutes: [{ name: 'Max' }]) to create both a Manufacturer and a nested User at once.
This is how you would setup your controller
class ManufacturersController
# ...
def new
#manufacturer = Manufacturer.new
#manufacturer.users.build
end
def create
#manufacturer = Manufacturer.create(manufacturer_params)
# ...
end
private
def manufacturer_params
params.require(:manufacturer)
.permit(
:name, :license_no, :contact_no, :address, :country,
:city, :pincode, :email_id,
users_attributes: [:email, :password, :confirm_password]
)
end
end
And your form:
<%= form_for(#manufacturer) do |f| %>
<%= f.text_field :name # manufacturer[name] %>
<%= f.text_field :license_no %>
...
<%= f.fields_for(:users) do |user_fields| %>
<%= user_fields.text_field :email # manufacturer[users_attibutes][1][email] %>
...
<% end &>
<% end %>
As #Venkat ch already has pointed out storing plaintext passwords in the database is really insecure. Use has_secure_password instead.