NoMethodError in Profiles#show undefined method `about' for nil:NilClass - ruby-on-rails

I am currently re-working my routes, which leads to a lot of mistakes in my Rails App. I am coming from something like
users/:user_id/profiles/id/reviews
to
/users/:user_id/profile/reviews
After registering a user gets redirected (redirect_after_sign_up) to a profile
/users/:user_id/profile/new
where the user can fill out the form (a allow nested attributes for profile)
<%= form_for(#user, url: user_profile_path, method: :post) do |form| %>
<div class="field">
<%= form.label :street %>
<%= form.text_area :street %>
</div>
<%= fields_for(:profile) do |profile_fields| %>
<div class="field">
<%= profile_fields.label :about %>
<%= profile_fields.text_area :about %>
</div>
<div class="field">
<%= profile_fields.file_field :avatar %>
<% profile_fields.label "Profile photo" %>
</div>
<% end %>
<div class="actions">
<%= form.submit "Save your profile", class: "btn btn-default" %>
</div>
<% end %>
After I click submit, these data won't save anywhere. The user also won't get redirected to the #show, as, there are obviously some problems with my profiles controller. Neither #show, nor #create works. Here is the controller
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
def show
#profile = current_user.profile
#review = Review.new
Review.where(profile: #profile)
end
def new
#user = User.eager_load(:profile).find(params[:user_id])
#profile = Profile.new
end
def edit
#profile = #user.profile
end
def create
#user = current_user
#profile = current_user.build_profile(profile_params)
respond_to do |format|
if #profile.save
format.html { redirect_to user_profile_path(current_user.id), notice: 'Profile was successfully created.' }
format.json { render :show, status: :created, location: #profile }
else
format.html { render :new }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #profile.update(profile_params)
format.html { redirect_to user_profile_path(current_user.id), notice: 'Profile was successfully updated.' }
format.json { render :show, status: :ok, location: #profile }
else
format.html { render :edit }
format.json { render json: #profile.errors, status: :unprocessable_entity }
end
end
end
# DELETE /profiles/1
# DELETE /profiles/1.json
def destroy
#profile.destroy
respond_to do |format|
format.html { redirect_to users_url, notice: 'Profile was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_profile
#profile = current_user.profile
end
def profile_params
params.permit(:about, :avatar)
end
end
I really need help adjusting the controller, so it works without a profile_id. Here is the show page, just in case:
<% if #profile == current_user.profile %>
<strong> Welcome </strong><%= current_user.first_name %>
<% else %>
<strong> This is a profile of </strong><%= #profile.user.first_name %> <%= #profile.user.last_name %>
<% end %>
<p>
<strong>About:</strong>
<%= #profile.about %>
</p>
<strong>Profile image</strong>
<%= image_tag(url_for(#profile.avatar), style: 'width:50px; height:50px;') %>
</p>
<%= render 'reviews/form' %>
<% #reviews.each do |review| %>
<%= review.user.first_name %> <%= review.user.last_name %> wrote <small> <%= time_ago_in_words(review.created_at) %> ago </small>
<p>
<%= review.content %>
<br>
<strong> Rating </strong><%= review.rating %>
</p>
<% end %>
<%= link_to 'Edit', edit_user_profile(current_user.profile) %>
<%= link_to 'Show other profiles', users_path %>
<div class="container">
Thank you.
P.S. I tried to work with a ProfileController (single), but this didn't work at all, as the app wouldn't find the controller.
UPDATE:
So, I tried to play with the form, looks like the form won't save neither to profile nor to user. Even if I get rid of the nested attributes, it still doesn't save. This stays unresoled ...

as i can see you're using fields_for, so check a structure od params which are send when posting. I suppose they may look like:
user: { :street, profile_attributes: { :about, :avatar } }
and if yes, you need to change the permitted params method to match what is actually send.
Next advise is to add accepts_nested_attributes_for :profile in user model, and use fields_for proper way by saving profile in addition to saving user, because current code is little messy (form_for user with fields for profile leading to profile controller).
If you don't wan't to deal with nested attributes you may also rewrite form as form_for #profile ...

Related

Ruby on Rails: How to extract URL parameter and insert the value inside a variable

I need to extract a parameter from my url and insert it into my database for a referral system.
Let's say this user, which is id = 1 has shared his link with another user, the url would be:
https://www.example.com/signup?referredBy=1
When the new user creates his account, I want the field referredBy to be assigned with the value from the referredBy parameter, which should be an Integer.
I've tried to do
#user.referredBy = [:referredBy]
But it didn't worked out.
Any help is appreciated.
Thank you so much.
EDIT
My index.html.erb is:
<% if current_user %>
Logged in as <%= current_user.nomeUsuario %>
<%= link_to "Log out", logout_path %>
<% end %>
<p id=”notice”><%= notice %></p>
<% else %>
<%= link_to "Sign up", signup_path %>
<%= link_to "Log in", login_path %>
<% end %>
My new.html.erb is:
<h1>New User</h1>
<% if current_user %>
<% controller.redirect_to root_url %>
<% else %>
<%= render 'form', user: #user %>
<%= link_to 'Back', login_url %>
<% end %>
My _form.html.erb is:
<%= form_with(model: user) do |form| %>
<% if user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% user.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name, "Full Name" %>
<%= form.text_field :nomeUsuario %>
</div>
<div class="field">
<%= form.label :name, "E-mail" %>
<%= form.text_field :email %>
</div>
<div class="field">
<%= form.label :name, "Password" %>
<%= form.password_field :password %>
</div>
<div class="field">
<%= form.label :name, "Password Confirmation" %>
<%= form.password_field :password_confirmation %>
</div>
<div class="field">
<%= form.label :name, "Tipo do Plano" %>
<%= form.select :tipoPlano, ["Gratuito", "Mensal", "Anual"], selected: "Gratuito" %>
</div>
<%= form.hidden_field :indicadoPor, params[:indicadoPor] %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
My user_controller.rb is:
class UsersController < ApplicationController
before_action :set_user, only: %i[ show edit update destroy ]
# GET /users/new
def new
#user = User.new
end
# GET /users/1/edit
def edit
end
# POST /users or /users.json
def create
#user = User.new(user_params)
set_tipoPlano
#user.indicadoPor = params[:indicadoPor]
respond_to do |format|
if #user.save
format.html { redirect_to root_url, notice: "User was successfully created." }
format.json { render root_url, status: :created, location: #user }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /users/1 or /users/1.json
def update
respond_to do |format|
if #user.update(user_params)
set_tipoPlano
format.html { redirect_to root_url, notice: "User was successfully updated." }
format.json { render :show, status: :ok, location: #user }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Only allow a list of trusted parameters through.
def user_params
params.require(:user).permit(:email, :password, :password_confirmation, :nomeUsuario, :tipoPlano, :valorPlano, :indicadoPor, :comissaoAcumuladaAtual, :comissaoASerRetirada)
end
def set_tipoPlano
if(#user.tipoPlano == "Gratuito")
#user.valorPlano = 0.0
elsif(#user.tipoPlano == "Mensal")
#user.valorPlano = 49.90
elsif(#user.tipoPlano == "Anual")
#user.valorPlano = 39.90
end
end
end
If you need something else, please let me know! Thank you so much for the help.
ANSWER BELOW
I've fixed it.
I just had to change my form to:
<%= form.hidden_field :indicadoPor, value: params[:indicadoPor] %>
I forgot the =, so the form wasn't being rendered. Also, I've removed the #user.referredBy = params[:referredBy] from my controller. Everything is fine now.
Thank you guys, gals and non-binaries for the help so far!
[:referral]
This is an array with a single value. That value is a symbol :referral.
I'm not sure what type your referredBy column is but it's almost certainly going to complain about being given an array of symbols.
You want
params[:referral]
params is a hash like object containing the params in the url/(and sometimes body). So params[:referral] looks up the :referral symbol in the params hash and returns whatever the user provided.

Add data to table referenced with foreign key in Rails

I have two models: Question and Options. Question has has_many relation with Options. I need to add options to question whenever I create a new question. I have written the code but I am not able to send data to the options of Question model. Whenever I create the question and add options in the form, the options to that question are empty. Where is the mistake?
Models
class Question < ApplicationRecord
belongs_to :user
has_many :options
accepts_nested_attributes_for :options
end
class Option < ApplicationRecord
belongs_to :question
end
questions_controller.rb
# GET /questions/new
def new
#question = Question.new
#question.options.build(params[:options])
end
# GET /questions/1/edit
def edit
end
# POST /questions
# POST /questions.json
def create
#question = Question.new(question_params)
puts("---------------------Question options: --------------------------------------------")
puts(#question.options)
#question.user = current_user
respond_to do |format|
if #question.save
format.html { redirect_to #question, notice: 'Question was successfully created.' }
format.json { render :show, status: :created, location: #question }
else
format.html { render :new }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /questions/1
# PATCH/PUT /questions/1.json
def update
respond_to do |format|
if #question.update(question_params)
format.html { redirect_to #question, notice: 'Question was successfully updated.' }
format.json { render :show, status: :ok, location: #question }
else
format.html { render :edit }
format.json { render json: #question.errors, status: :unprocessable_entity }
end
end
_form.html.erb
<%= form_with(model: question, local: true) do |form| %>
<% if question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% question.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :body %>
<%= form.text_area :body %>
</div>
<%= form.fields_for :address do |a| %>
<div class="field">
<%= a.label :option1 %>
<%= a.text_area :body %>
</div>
<div class="field">
<%= a.label :option2 %>
<%= a.text_area :body %>
</div>
<% end %>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
For this case, I strongly recommend using a FormObject in place of accepts_nested_attributes_for. Here is a quick video on how to implement a FormObject. https://thoughtbot.com/upcase/videos/form_objects
Also, there is a related discussion here on why accepts_nested_attributes_for is not a great option.

Rails saving all my fields as nil

It creates the object, says that it was successfully created, but all fields are saved in the database with nil values. Only created_at and updated_at are saved normally.
Some methods of my controllers/admin/categories_controller.rb
def new
#admin_category = Category.new
end
# GET /admin/categories/1/edit
def edit
end
# POST /admin/categories
# POST /admin/categories.json
def create
#admin_category = Category.new(params[:category])
respond_to do |format|
if #admin_category.save
format.html { redirect_to admin_category_path(#admin_category), notice: 'Category was successfully created.' }
format.json { render :show, status: :created, location: admin_category_path(#admin_category) }
else
format.html { render :new }
format.json { render json: #admin_category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /admin/categories/1
# PATCH/PUT /admin/categories/1.json
def update
respond_to do |format|
if #admin_category.update(admin_category_params)
format.html { redirect_to #admin_category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #admin_category }
else
format.html { render :edit }
format.json { render json: #admin_category.errors, status: :unprocessable_entity }
end
end
end
This is my models/category model:
class Category < ActiveRecord::Base
belongs_to :category
end
This is my routes.br file
namespace :admin do
resources :categories
end
My views/admin/categories/_form.html.erb
<%= form_for(#admin_category, url: admin_categories_path) do |f| %>
<% if #admin_category.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#admin_category.errors.count, "error") %> prohibited this admin_category from being saved:</h2>
<ul>
<% #admin_category.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :is_active %><br>
<%= f.check_box :is_active %>
</div>
<div class="field">
<%= f.label :main_menu %><br>
<%= f.check_box :main_menu %>
</div>
<div class="field">
<%= f.label :category_id %><br>
<%= f.number_field :category_id %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
And when I try to edit, I get this error:
No route matches [PATCH] "/admin/categories"
I'm very newbie to Ruby on Rails, so I would apreciate any help!
Thanks!
You are only passing :category when creating a new Category:
def create
#admin_category = Category.new(params[:category])
Change it to Category.new(user_params) and try again. This will pass on all parameters you're creating and feed it to the database.
Also, permit the parameters you are trying to pass:
def user_params
params.require(:admin_category).permit(:name, :is_active, :main_menu, :category_id)
end
Strong Params:
#app/controllers/categories_controller.rb
class CategoriesController < ApplicationController
def create
#admin_category = Category.new category_params
end
private
def category_params
params.require(:category).permit(:name, :is_active, :main_menu, :category_id)
end
end
--
As a tip, if you're using nested objects with forms, you can pass both objects in an array to create the nested path:
#app/views/admin/categories/new.html.erb
<%= form_for [:admin, #admin_category] do |f| %>

Ruby on Rails Drop Down Box not committing to database (Model)

I have a rails form to collect information on people for a family tree application. There are two drop down boxes that are used to assign the parents of the person being edited/created, however when a selection is made in either, or both, of these boxes, it is not committed to the database. It doesn't throw any exceptions, however when I check the database, the fatherID and motherID fields remain as null.
Here is the complete code for the form:
Does anybody have any ideas where I'm going astray?
Thanks.
<%= form_for(#person) do |f| %>
<% if #person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#person.errors.count, "error") %> prohibited this person from being saved:</h2>
<ul>
<% #person.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :FirstName %><br>
<%= f.text_field :FirstName %>
</div>
<div class="field">
<%= f.label :LastName %><br>
<%= f.text_field :LastName %>
</div>
<div class="field">
<%= f.label :MaidenName %><br>
<%= f.text_field :MaidenName %>
</div>
<div class="field">
<%= f.label :Sex %><br>
<%= f.select(:Sex, options_for_select([['Male', 'M'], ['Female', 'F']]))%>
</div>
<div class="field">
<p>Parents:</p>
Mother: <%= select(:motherID, options_from_collection_for_select(Person.all, :id, :FirstName), :include_blank => true)%>
Father: <%= select(:fatherID, options_from_collection_for_select(Person.all, :id, :FirstName), :include_blank => true)%>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Controller code
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# GET /people
# GET /people.json
def index
#people = Person.all
end
# GET /people/1
# GET /people/1.json
def show
end
# GET /people/new
def new
#person = Person.new
end
# GET /people/1/edit
def edit
end
# POST /people
# POST /people.json
def create
#person = Person.new(person_params)
respond_to do |format|
if #person.save
format.html { redirect_to #person, notice: 'Person was successfully created.' }
format.json { render action: 'show', status: :created, location: #person }
else
format.html { render action: 'new' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /people/1
# PATCH/PUT /people/1.json
def update
respond_to do |format|
if #person.update(person_params)
format.html { redirect_to #person, notice: 'Person was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #person.errors, status: :unprocessable_entity }
end
end
end
# DELETE /people/1
# DELETE /people/1.json
def destroy
#person.destroy
respond_to do |format|
format.html { redirect_to people_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
#person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:FirstName, :LastName, :MaidenName, :Sex)
end
end
Model Code
class Person < ActiveRecord::Base
has_ancestry
end
:motherID and :fatherID need to be in params.require(:person).permit(:FirstName, :LastName, :MaidenName, :Sex) otherwise the controller does not pass these values to the model for them to be saved.
For more information about strong parameters, see the rails guide: http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters

can't use #user in form_for in rails 4 getting a nil error

I know that there are many questions a but every solution that i've tried did not work.
I am trying to create a sign in form, but I am getting the following error
First argument in form cannot contain nil or be empty
replacing #user with User.new will solve the error , but than I can't check for #user.errors.any..
any suggestions?
<h1>Sign up</h1>
<div class="row">
<div class="span6 offset7">
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation %>
<br>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
and my controller code is
class UsersController < ApplicationController
before_action :set_user, only: [:show]
def new
#user = User.new
end
# POST /user
# POST /user.json
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render action: 'show', status: :created, location: #user }
else
format.html { render action: 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /user/1
# PATCH/PUT /user/1.json
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def edit
end
# DELETE /user/1
# DELETE /user/1.json
def destroy
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
In your edit, update and delete actions, you do not set #user.
You should maybe change your before filter:
before_action :set_user, only: [:show, :edit, :update, :destroy]
or
before_action :set_user, except: [:index, :new]

Resources