Rails update not saving values - ruby-on-rails

Please help me. I've been tearing out my hair trying to figure out what I feel should be a simple thing.
My update function "succeeds" but it does not actually save the new values. The console log doesn't throw an error, but it does say "Unpermitted parameter: profiles"
edit.html.erb
<div class="col-md-7 col-md-offset-3 main">
<% provide(:title, "Edit user")%>
<center><h1>Update your profile</h1></center>
<%= form_for(#person) do |f| %>
<%= render 'shared/error_messages' %>
<div class="col-md-12">
<%= render 'layouts/profilefields', f: f %>
<%= f.submit "Save Changes", class: "btn btn-large btn-primary" %>
</div>
<% end %>
</div>
_profilefields.html.erb
<%= f.fields_for :profiles do |prf|%>
<!--
<% if !#profileInfo["avatar"].blank? %>
<%= image_tag #contactInfo.avatar_url(:medium).to_s, :class=>"profilePhoto" %>
<% end %>
<div class="photoPreview">
<i class="fa fa-upload photoUpload"></i>
<p id="uploadClick">Click to Upload</p>
</div>
<%= prf.file_field :avatar, accept: 'image/png,image/gif,image/jpeg, image/jpg', id: 'uploadAvatar' %>
<p class="deletePhoto">Delete</p>
-->
<%= prf.label :about %>
<%= prf.text_field :about, :class => "form-control" %>
<%= prf.label :why %>
<%= prf.text_field :why, :class => "form-control" %>
<%= prf.label :goals %>
<%= prf.text_field :goals, :class => "form-control" %>
<%= prf.hidden_field :traveler_id, value: current_traveler.id %>
<% end %>
travelers_controller.rb
class TravelersController < ApplicationController
def edit
#person = Traveler.find(params[:id])
#profileInfo = Profile.find_or_initialize_by(traveler_id: params[:id])
##profileInfo[:email] = current_traveler.email
#This builds the form
#person.build_profile(#profileInfo.attributes)
end
def show
end
def update
#trav = Traveler.find(params[:id])
#prof = Profile.find_or_create_by(traveler_id: current_traveler.id)
if #trav.update(update_traveler_params)
flash[:success] = "Profile updated"
redirect_to feed_path
else # Failed. Re-render the page as unsucessful
render :edit
end
end
private
def update_traveler_params
params.require(:traveler).permit(:id, profiles_attributes: [:id, :first_name, :last_name, :about, :why, :goals,
:avatar, :traveler_id])
end
end
and the models
class Profile < ApplicationRecord
belongs_to :traveler, foreign_key: "traveler_id"
end
class Traveler < ApplicationRecord
# Include default devise modules. Others available are:
# , :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_one :profile
accepts_nested_attributes_for :profile, update_only: true, allow_destroy: true
end
and the schema. Is the profile foreignkey set up correctly?
ActiveRecord::Schema.define(version: 20160825224710) do
create_table "profiles", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "first_name"
t.string "last_name"
t.text "about", limit: 65535
t.text "why", limit: 65535
t.text "goals", limit: 65535
t.string "avatar"
t.integer "traveler_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["traveler_id"], name: "index_profiles_on_traveler_id", using: :btree
end
create_table "travelers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
end
end

I believe the problem is caused by your use of "profiles", when your association is actually a has_one.
Try changing:
profiles_attributes to profile_attributes in travellers_controller#update_traveler_params
:profiles to :profile in _profilefields.html.erb

Related

I can't show the creator of a comment in the view part

I am doing a facebook clone app and I am implementing comments in posts. I can show the comments from the post but when I try to put the name of the creator of the comment, it show me an error.
The error that I get
This is what I have right now.
schema
ActiveRecord::Schema.define(version: 2019_09_02_233213) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "comments", force: :cascade do |t|
t.text "body"
t.bigint "user_id", null: false
t.bigint "post_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["post_id"], name: "index_comments_on_post_id"
t.index ["user_id"], name: "index_comments_on_user_id"
end
create_table "likes", force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "post_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["post_id"], name: "index_likes_on_post_id"
t.index ["user_id"], name: "index_likes_on_user_id"
end
create_table "posts", force: :cascade do |t|
t.bigint "user_id", null: false
t.text "body", default: "", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_posts_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "name", default: "", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "comments", "posts"
add_foreign_key "comments", "users"
add_foreign_key "likes", "posts"
add_foreign_key "likes", "users"
add_foreign_key "posts", "users"
end
users show views
<h1><%= #user.name %></h1>
<% #posts.each do |post| %>
<%= post.body %><br>
<%= form_for(post.comments.build, url: post_comments_path(post)) do |f| %>
<%= f.text_area :body %><br>
<%= f.submit 'Comment' %><br>
<% end %>
<% post.comments.each do |comment| %>
<%= comment.user.name %>
<%= comment.body %><br>
<% end %>
<% end %>
users controllers
class UsersController < ApplicationController
before_action :authenticate_user!
def index
#users = User.all
end
def show
#user = User.find(params[:id])
#posts = #user.posts
end
end
comment controllers
class CommentsController < ApplicationController
def create
post = Post.find(params[:post_id])
comment = post.comments.build(comment_params.merge(user: current_user))
if comment.save
redirect_back(fallback_location: root_path)
else
flash[:error] = comment.errors.full_messages
redirect_back(fallback_location: root_path)
end
end
def destroy
end
private
def comment_params
params.require(:comment).permit(:body)
end
end
user model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :posts
has_many :likes
has_many :comments
end
post model
class Post < ApplicationRecord
validates :body, presence: true
belongs_to :user
has_many :likes
has_many :comments
end
comment model
class Comment < ApplicationRecord
validates :body, presence: true
belongs_to :user
belongs_to :post
end
It looks like you have a comment that is not attached to a user. This could just be test data that has been left hanging around but you should cater for this and only display the user if there is one
<%= comment.user.name %>
Could become
<%= comment.user.name unless comment.user.blank? %>
You should also cater for the occasion when a name is not present.
Anyway, if you add that fix you will be able to tell more easily which records are not what you expect them to be and sort them appropriately
Something like this might help
<% if comment.user %>
<%= comment.user.name unless comment.user.name.blank? %>
<%else%>
<p> The comment <%= comment.body %> has no user attached. Please fix this. The comment ID is: <%=comment.id%></p>
<%end%>
Code is untested so if you have a problem let me know
You can check for blank? if you prefer
UPDATE
<% post.comments.each do |comment| %>
<% if comment.user %>
<%= comment.user.name %>
<%= comment.body %><br>
<%else%>
No user for <%= comment.body %>
<%end%>
<% end %>

rails 6 Devise create user & account ActiveModel::UnknownAttributeError (unknown attribute 'accounts' for User.):

Hi I have a rails 6 app where i want the user to create an account on sign up.
I am using devise for authentication.
I have two models User(devise) and account
class User < ApplicationRecord
has_merit
enum role: [:user, :tech, :admin, :manager]
belongs_to :account
accepts_nested_attributes_for :account
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :admin
end
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :invitable, :registerable,
:recoverable, :rememberable, :validatable
end
class Account < ApplicationRecord
has_many :users, dependent: :destroy
has_many :clients, dependent: :destroy
end
During signup(devise registration) I want the user to to create an account.
In the console it works:
User.create(email: 'test#email.com', password: "test", password_confirmation: "test, account_attributes: {name: "testaccount"})
creates as expected.
but when i use the front end form
<h2>Sign up</h2>
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :email,
required: true,
autofocus: true,
input_html: { autocomplete: "email" }%>
<%= f.simple_fields_for :accounts do |a| %>
<%= a.input :name %>
<% end %>
<%= f.input :password,
required: true,
hint: ("#{#minimum_password_length} characters minimum" if #minimum_password_length),
input_html: { autocomplete: "new-password" } %>
<%= f.input :password_confirmation,
required: true,
input_html: { autocomplete: "new-password" } %>
</div>
<div class="form-actions">
<%= f.button :submit, "Sign up" %>
</div>
<% end %>
I get a funky error
ActiveModel::UnknownAttributeError (unknown attribute 'accounts' for User.):
My Schema
create_table "accounts", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.integer "role"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "sash_id"
t.integer "level", default: 0
t.bigint "account_id"
t.index ["account_id"], name: "index_users_on_account_id"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Your help is much appreciated and if you need more info please let me know.
You're getting UnknownAttributeError because you don't have a column in your users table called accounts.
I recommend you do it that way:
#user.rb
has_one :account, inverse_of: :user
accepts_nested_attributes_for :account
#account.rb
belong_to :user
#controller
def new
#user = User.new
#user.build_account
end
Source: https://github.com/plataformatec/simple_form/wiki/Nested-Models#nested-models

Pass a foreign table in a "form_for"

I have two model
user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :personal
before_create :generate_profile
end
and personal.rb
class Personal < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
end
and in my controller i have :
def createinfo
#user = current_user
#personal = #user.personal
end
I want to do a form for like that :
<%= form_for #personal do |f| %>
Trigramme : <%= f.text_field :trigramme, :input_html => { :value => 'blabla' } %><br />
Nom : <%= f.text_field :nom %><br />
Prenom : <%= f.text_field :prenom %><br />
Poste : <%= f.text_field :poste %><br />
Bio : <%= f.text_area :bio %><br />
<%= f.submit %>
<% end %>
But i have an error and I don't know how to resove that. I think the path current_user.personal is not accepted by form_for although it print the correct thing when I only put current_user.personal.trigramme in the code.
undefined method `personal_path' for #<#<Class:0x8e15a28>:0x8e15308>
do you know how can I do this form?
EDIT : My route.rb
Rails.application.routes.draw do
devise_for :users
root 'static_pages#cvpage'
get 'home' => 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'cvpage' => 'static_pages#cvpage'
get 'createinfo' => 'static_pages#createinfo'
end
EDIT 2 schema.rb :
create_table "personals", force: :cascade do |t|
t.string "trigramme"
t.string "nom"
t.string "prenom"
t.string "poste"
t.text "bio"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "personals", ["user_id"], name: "index_personals_on_user_id"
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
YEAHH! I solve my problem (take a lot of time)
I put in my personal controller this :
def update
#user = current_user
#personal = #user.personal
if #personal.update_attributes(personal_params)
# if update is successful
else
# if update is unsuccessful
end
redirect_to home_path
end
def personal_params
params.require(:personal).permit(:trigramme, :nom, :prenom, :poste, :bio)
end
And i put in my view this form :
<%= form_for(#personal, html: { method: :put }) do |f| %>
Trigramme : <%= f.text_field :trigramme %><br />
Nom : <%= f.text_field :nom %><br />
Prenom : <%= f.text_field :prenom %><br />
Poste : <%= f.text_field :poste %><br />
Bio : <%= f.text_area :bio %><br />
<%= f.submit %>
Thank you to all of you !!

How to add multiple images in rails site

I am trying to add several images to my site and am not quite sure how the routing works.
Here is my index.html.erb page
<%= render 'pages/home' unless user_signed_in? %>
<div id="properties" class="transitions-enabled">
<% #properties.each do |property| %>
<div class="box panel panel-default">
<%= link_to image_tag(property.image.url(:medium)), property_path(property) %>
<div class="panel-body">
<%= property.description %><br>
<strong><%= property.user.name if property.user %></strong>
<!-- <% if property.user == current_user %>
<div class="actions">
<%= link_to 'Edit', edit_property_path(property) %>
<%= link_to 'Destroy', property, method: :delete, data: { confirm: 'Are you sure?' } %>
</div> -->
<% end %>
</div>
</div>
<% end %>
</div>
And I think it's after this line <%= link_to image_tag(property.image.url(:medium)), property_path(property) %> that I want to add another image.
Here is my _formfield.html.erb file where I ask for two images
<div class="form-group">
<%= f.label :image %><br>
<%= f.file_field :image, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :street_image %><br>
<%= f.file_field :street_image, class: "form-control" %>
</div>
How do I show the :streetimage properly?
And this is my property model:
class Property < ActiveRecord::Base
belongs_to :user
has_attached_file :image, :styles => { :medium => "300x300", :thumb => "100x100"}
validates_attachment_content_type :image, :content_type => ["image/jpg", "image/jpeg", "image/png"]
validates :image, presence: true
validates :description, presence: true
end
And here's my schema
ActiveRecord::Schema.define(version: 20150429054455) do
create_table "properties", force: :cascade do |t|
t.string "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.string "name"
t.string "street"
t.integer "zip"
t.string "state"
t.string "company"
t.string "city"
t.integer "price"
t.integer "space"
t.string "street_image_file_name"
t.string "street_image_content_type"
t.integer "street_image_file_size"
t.datetime "street_image_updated_at"
end
add_index "properties", ["user_id"], name: "index_properties_on_user_id"
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
It's working now. Looks like I had the wrong variable set and didn't run rake db:migrate before

Why does Devise keep asking me that the name can't be blank?

I am new to Rails, and I am working with Devise. The problem I am facing is that my form is not updating the name column of the user when they are signing up. I have the name attribute in the data table, but I can't seem to alter it using a form in devise registration.
<h2>Sign up</h2>
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>
<div><%= f.label :name %><br />
<%= f.text_field :name, :autofocus => true %></div>
<div><%= f.label :email %><br />
<%= f.email_field :email %></div>
<div><%= f.label :password %><br />
<%= f.password_field :password %></div>
<div><%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %></div>
<div><%= f.submit "Sign up" %></div>
<% end %>
<%= render "devise/shared/links" %>
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :posts
end
Scheme.rb
ActiveRecord::Schema.define(version: 20130622203624) do
create_table "posts", force: true do |t|
t.integer "user_id"
t.text "description"
t.integer "comments_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "title"
end
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
create_table "views", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", limit: 128, default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "views", ["email"], name: "index_views_on_email", unique: true, using: :btree
add_index "views", ["reset_password_token"], name: "index_views_on_reset_password_token", unique: true, using: :btree
end
If you are using rails4 you need strong parameters. If you need to implement extra parameters to devise, you could either create an additional 1-1 relation called profiles for users and store them there (better in the long run of app or if you have more user data) and I personally feel it to be much easier the incorporating your user data in the devise user table.
Alternatively you could do the following if you are using one or two attributes.
You need to permit the name parameter for devise. in your ApplicationController code, do this.
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
end
end
Refer more on this on devise wiki.
Need to make the following changes - and that should fix it
gem 'protected_attributes'
class RegistrationsController < Devise::RegistrationsController
before_filter :configure_permitted_parameters
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:name, :user_type,:email, :password, :password_confirmation)
end
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:name,:user_type,:email, :password, :password_confirmation, :current_password)
end
end

Resources