Setting Default Value in .build method - ruby-on-rails

Im trying to submit a nested form when you create a school, you can also create a admin with it. When I try to save the form with the default value of owner set to true and status set to active, it saves the form but doesnt save those values in the database
class SchoolsController < ApplicationController
before_filter :authenticate_admin!, except: [:index, :new, :create]
def show
#school = School.friendly.find(params[:id])
end
def new
#school = School.new
#admin = #school.admins.build(:owner => true, :status => "active")
end
def create
#school = School.new(school_params)
if #school.save
redirect_to new_admin_session_path
else
render 'new'
end
end
def edit
#school = School.find_by_slug(params[:id])
end
def update
#school = School.find_by_slug(params[:id])
if #school.update_attributes(school_params)
redirect_to :action => 'show', :id => #school
else
render :action => 'edit'
end
end
def team
#teams = Admin.all
end
private
def school_params
params.require(:school).permit(:school_name, :latitude, :longitude, :radius, admins_attributes: [ :first_name, :last_name, :email, :password, :password_confirmation, :image ])
end
end
class School < ActiveRecord::Base
has_many :admins
accepts_nested_attributes_for :admins
extend FriendlyId
friendly_id :school_name, use: :slugged
def should_generate_new_friendly_id?
school_name?
end
# Validation
validates :school_name, presence: true, uniqueness: true
validates :latitude, presence: true
validates :longitude, presence: true
validates :radius, presence: true, numericality: { only_integer: true }
end
%nav.navbar.navbar-default.navbar-fixed-top{role:"navigation"}
%div.container
%div.navbar-header
%button.navbar-toggle.collapsed{"data-toggle" => "collapse", "data-target" => "#navbar", "aria-expanded" => "false", "aria-controls" => "navbar"}
%span.sr-only Toggle Navigation
%span.icon-bar
%span.icon-bar
%span.icon-bar
%a.navbar-brand{"href" => "/", "id"=> "brand"} QuickAlert
%div#navbar.collapse.navbar-collapse
%ul.nav.navbar-nav.main-menu
%li.active
%a{"href" => "#"} Home
%li
%a{"href" => "#about"} About
%li
%a{"href" => "#contact"} Contact
%div.container-fluid
%div.row
%div.school-create
- if #school.errors.any?
%ul
- #school.errors.full_messages.each do |msg|
%li
= msg
%div#map-check
%h2.header School Info
= form_for #school do |f|
= f.label :school_name, "School Name"
= f.text_field :school_name, :class => 'form-control'
= f.label :latitude, "Latitude"
= f.text_field :latitude, :class => 'form-control', :id => "latitude"
= f.label :longitude, "Longitude"
= f.text_field :longitude, :class => 'form-control', :id => "longitude"
= f.label :radius, "Radius"
= f.text_field :radius, :class => 'form-control', :id => "radius"
%div.admin-fields
%h2.header Admin Info
= f.fields_for :admins do |ff|
= ff.label :first_name
= ff.text_field :first_name, :class => 'form-control'
= ff.label :last_name
= ff.text_field :last_name, :class => 'form-control'
= ff.label :email
= ff.text_field :email, :class => 'form-control'
= ff.label :password
= ff.password_field :password, :class => 'form-control'
= ff.label :password_confirmation
= ff.password_field :password_confirmation, :class => 'form-control'
= ff.file_field :image
= f.submit :class => 'submit-button btn btn-primary'

Related

Rails create/update more than one model at the same time

I have been struggeling with a nested form for a while and I dont know why it is not working.
The form updates/creates the venue without complaint, but not the associated venue_image.
Problem: I want to create/update a model and one of its associated models at the same time. Please note that the controllers are namespaced under "admin"
_form.haml
.col-md-12
= form_for([:admin, venue], html: { class: 'form-horizontal', multipart: true }) do |f|
- if venue.errors.any?
.col-md-12.alert.alert-danger{role: "alert"}
%h2
= pluralize(venue.errors.count, "Error")
%ul
- venue.errors.full_messages.each do |message|
%li= message
.form-group
= f.label :name, class: 'col-md-2 control-label'
.col-md-10
= f.text_field :name, class: 'form-control'
.form-group
= f.label :category, class: 'col-md-2 control-label'
.col-md-10
= f.text_field :category, class: 'form-control'
.form-group
= f.label :description, class: 'col-md-2 control-label'
.col-md-10
= f.text_area :description, rows: 5, class: 'form-control'
.form-group
= f.label :street, class: 'col-md-2 control-label'
.col-md-10
= f.text_field :street, class: 'form-control'
.form-group
= f.label :zip, class: 'col-md-2 control-label'
.col-md-10
= f.text_field :zip, class: 'form-control'
.form-group
= f.label :city, class: 'col-md-2 control-label'
.col-md-10
= f.text_field :city, class: 'form-control'
.form-group
= f.label :homepage, class: 'col-md-2 control-label'
.col-md-10
= f.url_field :homepage, class: 'form-control'
%h3 Add images
= f.fields_for(:venue_image, html: { class: 'form-horizontal', multipart: true }) do |vi|
.form-group
= vi.label :name, class: 'col-md-2 control-label'
.col-md-10
= vi.input :name, label: false, class: 'form-control'
.form-group
= vi.label :venue_id, class: 'col-md-2 control-label'
.col-md-10
= vi.input :venue_id, label: false, class: 'form-control'
.form-group
= vi.label :default, class: 'col-md-2 control-label'
.col-md-10
= vi.input :default, as: :radio_buttons, label: false, class: 'form-control radio radio-inline'
.form-group
= vi.label :image_file, class: 'col-md-2 control-label'
.col-md-10
= vi.file_field :image_file, label: false, class: 'form-control'
.actions
= f.submit 'Save', class: 'btn btn-primary pull-right'
= link_to 'Cancel', :back, class: 'btn btn-default'
venues_controller
class Admin::VenuesController < Admin::BaseController
before_action :set_venue, only: [:show, :edit, :update, :destroy]
def index
#venues = Venue.all
end
def show
end
def new
#venue = Venue.new
#venue.venue_images.build
end
def edit
end
def create
#venue = Venue.new(venue_params)
if #venue.save
redirect_to admin_venue_path(#venue), notice: 'Venue was successfully created.'
else
render :new
end
end
def update
if #venue.update(venue_params)
redirect_to admin_venue_path(#venue), notice: 'Venue was successfully updated.'
else
render edit_admin_venue
end
end
def destroy
#venue.destroy
redirect_to admin_venues_url, notice: 'Venue was successfully destroyed.'
end
private
def set_venue
#venue = Venue.find(params[:id])
end
def venue_params
params.require(:venue).permit(:name, :category, :description, :street, :zip, :city, :homepage,
venue_image_attributes: [:name, :default, :image_file])
end
end
venue_images_controller
class Admin::VenueImagesController < Admin::BaseController
def new
image = VenueImage.new
render locals: { image: image }
end
def create
# TODO: Remove # if possible
#image = VenueImage.new(venue_images_params)
if #image.save
redirect_to admin_venue_path(#image.venue.id), notice: 'Image was successfully created.'
else
render admin_new_venue_path
end
end
private
def venue_images_params
params.require(:venue_image).permit(:name, :default, :image_file, :venue_id)
end
end
routes
namespace :admin do
resources :venues do
resources :venue_images
end
resources :users
end
Thanks in advance for any help! Please let me know if you need more of the code.
Seems like you have a has_many relation with the Venue(i.e, has_many :venue_images), then this line
= f.fields_for(:venue_image, html: { class: 'form-horizontal', multipart: true }) do |vi|
should be
= f.fields_for(:venue_images, html: { class: 'form-horizontal', multipart: true }) do |vi|
And your venue_params method should be like below
def venue_params
params.require(:venue).permit(:id, :name, :category, :description, :street, :zip, :city, :homepage, venue_images_attributes: [:id, :name, :default, :image_file])
end
Notice the plural venue_images and also I added :id to venue_params for Update to work correctly.

Editing attribute saved with .build

Im trying to edit a field so that it goes in the database as the owner boolean being set to true when the user creates the account. I get the error undefined method `owner
= form_for #school do |f|
= f.label :school_name, "School Name"
= f.text_field :school_name, :class => 'form-control'
= f.label :latitude, "Latitude"
= f.text_field :latitude, :class => 'form-control'
= f.label :longitude, "Longitude"
= f.text_field :longitude, :class => 'form-control'
= f.label :radius, "Radius"
= f.text_field :radius, :class => 'form-control'
= f.fields_for :admins do |ff|
= ff.label :email
= ff.text_field :email, :class => 'form-control'
= ff.label :password
= ff.password_field :password, :class => 'form-control'
= ff.label :password_confirmation
= ff.password_field :password_confirmation, :class => 'form-control'
= f.submit :class => 'submit-button'
def new
#school = School.new
#school.admins.build
#school.admins.owner = true
end
def create
#school = School.new(school_params)
if #school.save
redirect_to :action => 'show', :id => #school
else
render 'new'
end
Because #school.admins is a collection of multiple admins, so it doesn't have the owner method, that exists on the individual admin objects within that collection.
When you call #school.admins.build it returns a new instance of Admin, but you're not doing anything with that instance. You need to put it in a variable, and then assign a value to its owner attribute. That will look like this:
#school = School.new
#admin = #school.admins.build
#admin.owner = true
But the build method takes an attributes argument, so you can shorten that to this:
#school = School.new
#admin = #school.admins.build(owner: true)
Don't forget that you'll also need to save this object at some point.

param is missing or the value is empty

I am new to Rails. Getting the error below. I understand what the issue is, but not sure how to fix it?
Error - param is missing or the value is empty: customer
def customer_params
params.require(:customer).permit(
:first_name,
:last_name,
:email,
:password,
:password_confirmation)
end
end
DetailsController.rb
class My::Account::DetailsController < MyController
def show
#customer = current_user
end
def update
#customer = current_user
#customer.update_attributes(customer_params)
if #customer.errors.any?
render :action => :show
else
redirect_to my_account_details_path, :notice => 'Account details updated'
end
end
private
def customer_params
params.require(:customer).permit(
:first_name,
:last_name,
:email,
:password,
:password_confirmation)
end
end
View
.account.container
.row
= render :partial => '/my/account/sidebar'
.section
%h2 Your account details
= simple_form_for #customer, :url => my_account_details_path, :method => :put, :html => { :class => 'form-horizontal'} do |form|
.field
= form.input :first_name
.field
= form.input :last_name
.field
= form.input :email, :as => :email
%hr
%h4 Leave password fields blank to keep the existing password
%hr
.field
= form.input :password, :input_html => { :value => '' }
.field
= form.input :password_confirmation, :input_html => { :value => '' }
.field-actions
%button.btn.btn-primary{type: "submit"} Save
It is because it is coming through as user and not customer. Which I believe is because you are using current_user which is a User and not a Customer (guessing from the code). Change it to be params.require(:user).permit(blah)

Split Form User Update Rails

Recently, I decided to split my User Form into an Edit & Account Form.
User Edit Form
-Name
-Username
-AboutMe
User Account Form
-Email
-Password
-Password Confirmation
The routes work fine and everything gets updated accordingly. But for some reason, when my User Model validates the Email Presence & it Fails, it renders the Edit Form with the appropriate Error Messages as oppose to the Account Form.
How can I set up my Update Method in my Controller to know which form to Render with the appropriate error messages?
Model
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :username
validates :username, :presence => true,
:length => { :maximum => 15 },
:format => { :with => VALID_UNAME_REGEX },
:uniqueness => { :case_sensitive => false }
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }, :if => :password #only validate if password changed!
validates :password_confirmation, presence: true, :if => :password
end
Views
Edit View
<%= form_for #user, :html => { :multipart => true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="statictitle">Your Profile</div>
<%= f.text_field :username, placeholder: "Username..", :class => "form-control" %>
<%= f.text_field :name, placeholder: "Name", :class => "form-control" %>
<%= f.text_area :bio, placeholder: "About yourself in 160 characters or less...", class: "textinput" %>
<%= f.submit "Update Profile", class: "btn btn-primary" %><br>
<% end %>
Account View
<%= form_for #user, :html => { :multipart => true } do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="statictitle">Your Account</div>
<%= f.text_field :email, placeholder: "Email", :class => "form-control" %>
<%= f.password_field :password, placeholder: "Password", :class => "form-control" %>
<%= f.password_field :password_confirmation, placeholder: "Password Confirmation", :class => "form-control" %>
<%= f.submit "Update Account", class: "btn btn-primary" %><br>
<% end %>
Controller
class UsersController < ApplicationController
def edit
#user = User.find_by_username(params[:id])
end
def account
#title = "Account"
#user = User.find_by_username(params[:id])
end
def update
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to user_url
else
render 'edit' ###I can't seem to figure out how to render the correct form
end
end
end
Routes
resources :users do
member do
get :account
end
end
You can check the HTTP Referer in this case which will tell you where the request came from and accordingly render your view.
for eg:
if URI(request.referer).path == edit_user_path
render :edit
else
render :account
end

Connection between three controllers rails

I have three controllers - users, stories, categories. I want when I am logged in as a administrator to create categories and then to write stories for every category. I did part of the task but in DB in table Stories category_id is empty and I cannot understand how to fix it. Here is part of my code:
stories/new.html.erb:
<%= form_for(#story) do |f| %>
<div class="field">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= f.collection_select :category_id, #categories, :id, :title %>
</div>
<div class="field">
<%= f.label :content %><br />
<%= f.text_area :content %>
</div>
<div class="actions">
<%= f.submit "Add" %>
</div>
<% end %>
stories_controller.rb:
class StoriesController < ApplicationController
before_filter :admin_user
def new
#story = Story.new
#categories = Category.all
#title = "Add news"
end
def create
#categories = Category.all
#story = current_user.stories.build(params[:story])
if #story.save
flash[:success] = "Successfullly added news"
redirect_to #story
else
#title = "Add news"
render 'new'
end
end
private
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
story.rb:
class Story < ActiveRecord::Base
attr_accessible :title, :content
belongs_to :user
belongs_to :category
validates :title, :presence => true
validates :content, :presence => true
validates :user_id, :presence => true
default_scope :order => 'stories.created_at DESC'
end
category.rb:
class Category < ActiveRecord::Base
attr_accessible :title
has_many :stories
validates :title, :presence => true,
:length => { :within => 6..40 }
end
user.rb:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
has_many :stories
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => true
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
def self.authenticate(email, submitted_password)
user = find_by_email(email)
return nil if user.nil?
return user if user.has_password?(submitted_password)
end
def self.authenticate_with_salt(id, cookie_salt)
user = find_by_id(id)
(user && user.salt == cookie_salt) ? user : nil
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt(string)
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
You need add attr_accessible :category_id to your story model
Its preventing mass assignment in your controllers create method. Alternatively you could pull out the category_id from your params hash and assign it on a separate line.

Resources