Rails - Nested Attributes issue - ruby-on-rails

I'm using nested attributes to user adresses.
class User < ApplicationRecord
accepts_nested_attributes_for :address, update_only: :true
I'm passing the address id as hidden field at sign-in.
<%= form_for (#user), :html => {:class => 'lead-form'} do |f| %>
<%= f.email_field :email, class:'form-control', placeholder: "Email", required: true %>
<%= f.password_field :password, class:'form-control', placeholder: "Senha", required: true %>
<%= f.fields_for :address do |addresses_form| %>
<%= addresses_form.hidden_field :address_id, :value => #address.id %>
<% end %>
<%= f.submit 'Pedir meu convite', class: "button lead-form-button" %>
<% end %>
The e-mail is validate as uniqueness. So, when somebody try to sign in with an already taken e-mail the address params are passed as nil and i get the error:
NoMethodError in Users#create
undefined method `id' for nil:NilClass
Any idea how can i fix that?
Here is my controller:
def new
#user = User.new
#address = #user.build_address
end
def create
#user = User.new(user_params)
if #user.save
log_in #user
flash[:success] = "Você está dentro. Esse é seu perfil! =) "
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:id, :primeiro_nome, :sobrenome, :email, :cpf, :telefone, :sexo, :data_de_nascimento, :password, address_attributes: [:id, :logradouro, :bairro, :cidade, :uf, :complemento, :cep])
end
ps: The association is one to one. How can i call the address attributes if i don't pass as hidden.

Address belongs to user? If yes, you just call #user.address

Maybe you should try using try method:
<%= addresses_form.hidden_field :address_id, :value => #address.try(:id) %>

Related

Rails update model wont work : No route matches, missing required keys: [:id]

I just started working on my second Rails project and am having some trouble with something that seems pretty basic. I am completely confounded though.
I've set up two models, User and Profile. A Profile belongs_to a User and the User has_one Profile.
I am setting up the edit form for a Profile right now and cannot get past this. The edit form loads correctly and inserts the data in the database but when I submit the form I get the following error
No route matches {:action=>"show", :controller=>"profiles", :format=>nil, :id=>#<Profile id: 7, user_id: 7, content: "Fill this in", created_at: "2015-01-08 19:08:22", updated_at: "2015-01-08 19:08:22", title: "fooobar", department: "one bar", school: "dsadsa", education: "two bar", academic_focus: "my bar is broken", website: "who bar is bokrbne">} missing required keys: [:id]
My models look like this
Class User < ActiveRecord::Base
has_one :profile, :class_name => 'Profile', :foreign_key => 'user_id'
attr_accessor :remember_token
end
class Profile < ActiveRecord::Base
belongs_to :user, :class_name => "User", :foreign_key => 'user_id'
attr_accessor :id
validates :content, presence: true, length: {maximum: 5000}
validates :user_id, presence: true
end
This is the form. I've tried various ways of adding a url: parameter to form_for but had no luck.
<%= form_for #profile do |f| %>
<%= f.label :title, class: 'col-lg-3 control-label' %>
<%= f.text_field :title, class: 'form-control' %>
<%= f.label :department, class: 'col-lg-3 control-label' %>
<%= f.text_field :department, class: 'form-control' %>
<%= f.label :school, class: 'col-lg-3 control-label' %>
<%= f.text_field :school, class: 'form-control' %>
<%= f.label :education, class: 'col-lg-3 control-label' %>
<%= f.text_field :education, class: 'form-control' %>
<%= f.label :academic_focus, class: 'col-lg-3 control-label' %>
<%= f.text_field :academic_focus, class: 'form-control' %>
<%= f.label :website, class: 'col-lg-3 control-label' %>
<div class="col-lg-8">
<%= f.text_field :website, class: 'form-control' %>
<%= f.hidden_field :id %>
<%= f.submit "Save changes", class: "btn btn-primary" %>
<% end %><!-- End of Form -->
Finally, here is the controller I am using.
class ProfilesController < ApplicationController
include ApplicationHelper
def index
# #profiles = Profile.limit(5)
#profiles = Profile.limit(15)
end
def show
#profile = Profile.find(params[:id])
end
def new
end
def create
#profile = Profile.new(profile_params)
if #profile.save
#successful save
flash[:success] = "Look at that. Ur Profile was ssaved"
redirect_to #profile
else
#unsuccesful
render 'new'
end
end
def edit
#user = current_user
#profile = Profile.find(#user.id)
end
def update
#profile = Profile.find(params[:id])
if #profile.update_attributes!(profile_params)
flash[:notice] = 'The User is successfully updated!'
redirect_to edit_profile_path
else
flash[:error] = #profile.errors.full_messages[0]
redirect_to edit_user_path
end
end
def view
#profile = Profile.find(params[:id])
end
private
def profile_params
params.require(:profile).permit(:id, :user_id, :content, :title, :department, :school, :education, :academic_focus, :website)
end
end
It is weird because I am using pretty much the exact same code I use for editing/creating users, but it isn't working. I figure it has something to do with relationship in the database.
Any insight would be much appreciated.
Thanks.
EDIT #1
Here's a photo of what happens when I submit the form
EDIT #2
If that image is too small here is a better one
http://i.imgur.com/Wu3v7Gu.png
EDIT #3
I changed the form_for arguments to
<%= form_for #profile, url: profile_update_path(#profile) do |f| %>
Now when the form is submitted I get this error
undefined method `profile_update_path' for #<#<Class:0x007fe1ae0e5618>:0x007fe1aca90458>
Remove the attr_accessor :id statement, it's likely interfering with the ActiveRecord default accessors in some way.

Allow customer too attach image to contact form

I have the below contact form and I would like to allow customers to send me an image as an attachment. I have added the field to the form but don't understand the following -
What migration do I create?
How do I attach the image to the
mailer?
View
<%= simple_form_for #inquiry, :method => :post do |f| %>
<%= f.input :spam, as: :hidden %>
<%= f.input :name %>
<%= f.input :phone %>
<%= f.input :email %>
<%= f.input :message %>
<%= f.file_field :image %> ## Attachment input here
<%= f.button :submit, 'Send' %>
<% end %>
Controller
def new
#inquiry = Inquiry.new
end
def create
redirect_to new_inquiry_path and return if params[:spam].present?
#inquiry = Inquiry.new(inquiry_params)
if #inquiry.valid?
InquiryMailer.admin(#inquiry).deliver
redirect_to inquiries_path
else
render :new
end
end
private
def inquiry_params
params.require(:inquiry).permit(:name, :email, :phone, :message)
end
Model
validates :name, presence: true
validates :email, presence: true
validates :phone, presence: true
validates :message, presence: true
inquiry_mailer.rb
class InquiryMailer < ActionMailer::Base
default from: "noreply#foo.com"
def admin(inquiry)
#inquiry = inquiry
mail to: "hello#foo.co.uk", subject: "Website Inquiry"
end
end
admin.text.erb
Website Inquiry
=========
Name: <%= #inquiry.name %>
Phone: <%= #inquiry.name %>
E-Mail: <%= #inquiry.email %>
Message: <%= #inquiry.message %>
You can make use of ActionMailer here
Ill provide an answer based upon your existing setup
You need to edit your mailer to look something like this
class InquiryMailer < ActionMailer::Base
default from: ENV['EMAIL_ADDRESS'] #I like to keep my email address hidden
def admin(inquiry)
#inquiry= inquiry
if inquiry.file
attachment_name = inquiry.file.original_filename
attachments[attachment_name] = inquiry.file.read
end
mail(to: ENV['EMAIL_ADDRESS'], subject: 'Website Inquiry')
end
end
You can keep admin.text.erb as it is and your controller stays the same
and within your form_for dont forget to add
<%= simple_form_for #inquiry, :method => :post, :multipart => true do |f| %>
so you the attachment can be added
Think thats it off the top of my head
Hope that helps, any questions then please ask

form_for omit specific fields from #user model

I have a user model: :name, :email, :password
Here is my form:
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.text_field :password %>
<%= f.submit "Save" %>
<% end %>
I want to display the form without :password, when I remove the password attribute and submit the form, the fields do not update in the database. I get a rollback.
You can do something like:
object.attribute = value
object.save(:validate => false)
This will never call your validation
But remember this will never validates your email and name fields as well if they are blank.
Commenting this line in my user model fixed the issue:
validates :password, length: { minimum: 6 }
However, as noted in the comments, it is not sufficient.
A user can edit their own profile, an admin can edit their own and others profiles.
Here is a solution:
def update
#user = User.find_by_id(params[:id])
if current_user?(#user)
if #user.update_attributes(user_params)
flash[:success] = "Your profile updated"
redirect_to #user
else
render 'edit'
end
else
if #user.update_attributes(admin_params)
flash[:success] = "Others profile updated"
redirect_to #user
else
render 'admin_edit_user'
end
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
def admin_params
params.require(:user).permit(:name, :email, :password) if current_user.admin?
end
If you want to skip validations on a particular form for a particular attribute, you could do the following.
Class User
attr_accessor :skip_password_validation
validate_presence_of :password, unless: -> { skip_password_validation }
end
This creates a virtual attribute that you can set and read but won't get persisted in the database.
Then you can put a hidden field for :skip_password_validation in whatever form you want and it will skip the validations.
<%= f.hidden_field :skip_password_validation, value: true %>
You'll also have to add this param to the user_params in the controller.

Instantiate empty model in partial view?

What is the proper way to have a form in a partial view reference an empty model in order to handle validation properly as defined on the model. Should I instantiate a new, empty model in the partial view and pass it through to the form? Here is what I'm working with...
MODEL
class NewsletterSignup < ActiveRecord::Base
def self.columns()
#columns ||= [];
end
def self.column(name, sql_type = nil, default = nil, null = false)
columns << ActiveRecord::ConnectionAdapters::Column.new(name, default, sql_type, null)
end
def persisted?
false
end
column :first_name, :string
column :last_name, :string
column :email, :string
column :zip, :string
validates :first_name, :last_name, :email, :zip, :presence => true
validates :email, :format => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates :zip, :format => /^\d{5}$/
end
Partial View
<%
signup = newsletter_signup.new
%>
<%= simple_form_for(signup, ...) do |f| %>
<%= f.input :first_name, :label => "First Name:" %>
<%= f.input :last_name, :label => "Last Name:" %>
<%= f.input :email, :label => "Email:" %>
<%= f.input :zip, :label => "Zip:" %>
...
<% end %>
But I can't seem to instantiate a new model like this. I assume I have to reference it in the view. (Note, I'm new to rails but have a decade+ of professional software development experience, so I apologize if some of rails constructs seem foreign to me and I may just be overlooking something simple!)
If your controller looks like this
def new
Model.new
end
def create
#model = Model.new(params[:model])
if #model.save
redirect root_path, notice: "Saved"
else
render action: 'new'
end
end
def edit
Model.find(params[:id])
end
def update
if #model.update(params[:model])
redirect root_path, notice: "Updated"
else
render action: 'edit'
end
end
You can have views like:
# new.html.erb
<%= render 'form' %>
# edit.html.erb
<%= render 'form' %>
# _form.html.erb
<%= form_for #model do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
...
<% end %>

NoMethodError raised following Railscast #250

I'm following the 'Authentication from scratch' railscast but cannot get it to work.
Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
redirect_to products_path, notice: 'User created successfully'
else
render 'new'
end
end
end
Model:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation
validates_uniqueness_of :email
end
users#new form:
<h1>Sign up form</h1>
<%= form_for #user do |f| %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation %>
<%= f.submit %>
<% end %>
When I try to go to the new user form it throws up a NoMethodError - undefined method 'email' referring to the line that has 'f.text_field :email'.
What am I missing here?
Thanks any help appreciated.
Your users table does not have an email column. Please run a migration to add the column to your users table.

Resources