Rails create does not save params from checkbox - ruby-on-rails

I am creating a website where a user (interviewer) can create a position (a job opening).
Even if the params are sent, my create action does not save them except for the current_user.
This is what I send:
positions_controller.rb
def new
#position = Position.new
end
def create
#position = Position.new(position_params)
#position.interviewer = current_interviewer
if #position.save
redirect_to position_path(#position)
flash[:success] = "You created a new position/opening"
else
render :new
end
raise
end
private
def set_position
#position = Position.find(params[:id])
end
def position_params
params.require(:position).permit(:title, :skills, :interviewer)
end
end
_form.html.erb
<%= simple_form_for [#interviewer, #position] do |f| %>
<%= f.input :title, required:true %>
<%= f.input :skills, as: :check_boxes, collection:[
['Python', "python"],
['Java', "java"],
['JavaScript', "javascript"],
['Ruby', "ruby"],
['C++', "c++"],
['Node.js', "node"],
['React', "react"],
['Django', "django"],
['Rails', "rails"],
['SQL', "sql"],
['Doker', "doker"],
['AWS', "aws"],
['Vue.js', "vue"],
['Marketing', "Marketing"],
['HR', "hr"],
['Finance', "finance"],
['IT', "it"],
], input_html: { multiple: true } %>
<%= f.submit "Submit position", class: "btn btn-primary" %>
<% end %>
position.rb
class Position < ApplicationRecord
validates :title, presence: true
belongs_to :interviewer
end
schema
create_table "positions", force: :cascade do |t|
t.string "title"
t.bigint "interviewer_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "candidate_id"
t.string "candidatures", default: [], array: true
t.string "skills"
t.index ["candidate_id"], name: "index_positions_on_candidate_id"
t.index ["interviewer_id"], name: "index_positions_on_interviewer_id"
end
My alternative was to replace the create code with:
#position = current_interviewer.positions.new(position_params)
but it still does not work.

Since you have a input_html: { multiple: true } for the params skills, you need to add the following in positions_controller.rb:
def position_params
params.require(:position).permit(:title, :interviewer, :candidate, skills:[])
end
Basically, your skills will be saved as an array if you allow input_html: { multiple: true } for a collection
In addition, you are not passing any params for candidate

In your table, you have interviewer_id but in your permitted params you have interviewer.
Change your params to permit interviewer_id instead.
Also, in your form you have <%= f.input :title, required:true %> Presence is required by default (at least with simple_form). You don't need to declare it in the form, but you should still keep it in your Model.

Related

Added a detail to Users, but value doesn't get picked up

I added an extra field in devise when a user signs up: "barge_name", when i go to the sign up page I enter a barge_name, email address and password this all works.
But when i try rails c, User.first is says barge_name is nil, I don't know why the value doesn't get picked up when signing up? Can someone help me with this?
#<User id: 1, email: "barcelona#gmail.com", created_at: "2019-10-31 17:43:21", updated_at: "2019-10-31 17:43:21", barge_name: nil>]
schema
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.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "barge_name"
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
migration files
class AddDetailsToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :barge_name, :string
end
end
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
end
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 :barge_name,
required: true,
autofocus: true,
input_html: { autocomplete: "bargename" }%>
<%= f.input :email,
required: true,
autofocus: true,
input_html: { autocomplete: "email" }%>
<%= 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 %>
<%= render "devise/shared/links" %>
controller
class PositionsController < ApplicationController
def new
#position = Position.new
end
def index
#positions = Position.all
end
def show
#position = Position.find(params[:id])
end
def create
#position = Position.new(position_params)
if #position.save!
redirect_to #position
PositionMailer.general_message(#position).deliver
else
render :new
end
end
private def position_params
params.require(:position).permit(:date, :time, :activity, :tripnumber)
end
end
Started POST "/users" for ::1 at 2019-11-01 18:15:31 +0100
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"K1WdKPpHZKESmfr7tZqi7yj2qM1SMIZWpXconGMbaZMZYrU1VRrpD6plMu2i79m6tWWYdAHQM98sPJzv2bDi4w==", "user"=>{"barge_name"=>"test", "email"=>"test#gmail.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
Unpermitted parameter: :barge_name
You have to add the new param like this.
application_controller.rb
before_action :configure_permitted_parameters, if: :devise_controller?
...
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:barge_name])
devise_parameter_sanitizer.permit(:account_update, keys: [:barge_name])
end
Take notice of the two lines, one is for sign_up and one is for account_update, so new and edit actions basically.

Rails 5: find_or_create_by not saving all the params

I have a form that should send info. One of the inputs is "empresa_id", and it's represented by a collection. I have checked in the server the form send the information I want. The thing is this field (only that one) is not saved when I run find_or_create_by. I've checked strong params and everything seem fine there.
SuscriptorsController
def create
#suscriptor = Suscriptor.new(suscriptor_params)
byebug #In this point #suscriptor.empresa_id has a correct value
if !#suscriptor.valid?
flash[:error] = "El email debe ser válido"
render 'new'
else
#suscriptor = Suscriptor.find_or_create_by(email: #suscriptor.email)
if #suscriptor.persisted?
if (#suscriptor.email_confirmation == true)
flash[:notice] = "Ya estás registrado/a"
redirect_to root_path
else
SuscriptorMailer.registration_confirmation(#suscriptor).deliver
end
else
flash[:error] = "Ha ocurrido un error. Contáctanos desde la sección contacto y explícanos"
render 'new'
end
end
private
def suscriptor_params
params.require(:suscriptor).permit(:email, :email_confirmation, :token_confirmation, :subtitle, :empresa_id)
end
Form view
<%= simple_form_for(#suscriptor) do |f| %>
<div class="input-group">
<div class="col-md-12">
<div class="form-group text">
<%= f.input :email, class: "form-control", placeholder: "tucorreo#email.com", required: true %>
<%= f.invisible_captcha :subtitle %>
<small id="emailHelp" class="form-text text-muted">Lo guardaremos y usaremos con cuidado.</small>
<%= f.input :empresa_id, collection: Empresa.all %>
</div>
<div class="input-group-append">
<%= f.submit "¡Hecho!", class: "btn btn-primary" %>
</div>
</div>
<% end %>
schema.rb
create_table "suscriptors", force: :cascade do |t|
t.string "email"
t.boolean "email_confirmation"
t.string "token_confirmation"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "empresa_id"
end
suscriptor.rb
class Suscriptor < ApplicationRecord
belongs_to :empresa, optional: true
before_create :confirmation_token
attr_accessor :subtitle
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 }, uniqueness: { case_sensitive: false }, format: { with: VALID_EMAIL_REGEX }
def confirmation_token
if self.token_confirmation.blank?
self.token_confirmation = SecureRandom.urlsafe_base64.to_s
end
end
end
In your find_or_create_by, your pass only the #suscriptor.email, and reassing the #suscriptor variable with the created suscriptor.
According API dock, you should pass a block to 'create with more parameters':
Suscriptor.find_or_create_by(email: #suscriptor.email) do |suscriptor|
suscriptor.empresa_id = #suscriptor.empresa_id
end
Be careful to not reassign #suscriptor variable before use the parameters.
You can read more about find_or_create_by in https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by
Hope this helps!

Rails 4 - Unpermitted parameters for nested param despite whitelisting

I have two models user_item and user_item_images.
schema.rb
create_table "user_item_images", force: :cascade do |t|
t.integer "user_item_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "picture"
end
create_table "user_items", force: :cascade do |t|
t.integer "user_id"
t.integer "item_id"
t.integer "status", default: 0
t.boolean "hide_banner", default: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "picture"
t.string "declined_reason"
end
I have a form where the user should submit a new user_item. The only field in the form is for pictures where the user can upload multiple pictures. On success, a single new user_item is created along with a new user_item_image for each picture that is uploaded.
form
<%= simple_form_for :user_item, url: user_items_path, html: {multipart: true} do |user_item_builder| %>
<%= user_item_builder.input :item_id, as: :hidden, input_html: { value: "#{#item.id}" } %>
<%= user_item_builder.simple_fields_for :user_item_images do |user_item_images_builder| %>
<%= user_item_images_builder.input :picture, as: :file, label: false, name: "user_item_images[picture][]", input_html: { multiple: true } %>
<% end %>
<% end %>
user_item_controller.rb
def create
#user_item = current_user.user_items.new(user_item_params)
raise 'foo'
if #user_item.save
params[:user_item][:user_item_images]['picture'].each do |a|
#user_item_image = #user_item.user_item_images.create!(:picture => a)
end
# Sends email to user when item request is created.
itemMailer.user_item_submission_email(current_user, #user_item.item).deliver_later
flash[:notice] = "Thank you for your item request!"
else
#user_item.errors.full_messages.each do |message|
flash[:alert] = message
end
end
redirect_to item_path(#user_item.item)
end
private
def user_item_params
params.require(:user_item).permit(:item_id, user_item_images_attributes: [:user_item_id, :picture])
end
user_item.rb
belongs_to :user
has_many :user_item_images
mount_uploader :picture, PictureUploader
accepts_nested_attributes_for :user_item_images
user_item_image.rb
mount_uploader :picture, PictureUploader
belongs_to :user_item
When I submit the form I get Unpermitted parameter: user_item_images in the console and I can't figure out why.
Change this:
<%= ..., name: "user_item_images[picture][]", ... %>
to this:
<%= ..., name: "user_item_images_attributes[picture][]", ... %>

Append a string to an array through strong parameters using << or Find_By_Sql in Rails

I am trying to append a string value to two array columns ("good_product" & "bad_product") of a Postgresql model ("product.rb") using strong parameters with user input from form_for text fields. I have found two ways (<< & find_by_sql) to achieve this goal but can't get either to work.
For example, "Product 3" submitted through form_for input should be added to {"Product 1", "Product 2", _______ } (if other products exist in the array) OR an empty array (if no product added yet).
Model: product.rb
class Product < ActiveRecord::Base
serialize :good_product, Array
serialize :bad_product, Array
end
Controller: products.controller.rb
def new
#product = Product.new
end
def create
#product = Product.new(product_params)
#product.good_product ||= []
#product.bad_product ||= []
#product.good_product << :good_product
#product.bad_product << :bad_product
redirect_to '/products'
end
private
def product_params
params.require(:product).permit(:good_product => [], :bad_product => [])
end
end
View: new.html.erb
<%= form_for #product, url: products_path do |f| %>
<%= f.label :good_product, "Good Product" %>
<%= f.text_field :good_product %>
<%= f.label :bad_product, "Bad Product" %>
<%= f.text_field :bad_product %>
<%= f.submit 'Submit' %>
<% end %>
Schema: schema.rb
create_table "products", force: :cascade do |t|
t.string "good_product", default: [], array: true
t.string "bad_product", default: [], array: true
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "products", ["user_id"], name: "index_products_on_user_id", using: :btree
Alternatively, instead of "<<", I tried this in the Controller:
def create
#product = Product.new(product_params)
Product.find_by_sql(["UPDATE products SET good_product = array_append(good_product, '?') WHERE user_id = ?", #product.good_product, current_user]);
Product.find_by_sql(["UPDATE products SET bad_product = array_append(bad_product, '?') WHERE user_id = ?", #product.bad_product, current_user]);
redirect_to '/products'
end
Thank you all for your help!

5 form elements present, but only 4 are saving to the database. Rails

I am having a problem with my database. I am able to save all the elements of my form into the database but it is leaving out ":captcha" for some reason. :email, :first_name, :last_name and :user_message are all saving, but :captcha is not.
HTML form views/pages/index.html.erb
<%= form_for(#message) do |f| %>
<%= f.text_field :first_name, :class => "message_name_input message_input_default", :placeholder => " First Name" %>
<br><br>
<%= f.text_field :last_name, :class => "message_name_input message_input_default", :placeholder => " Last Name" %>
<br><br>
<%= f.text_field :email, :required => true, :class => "message_email_input message_input_default", :placeholder => " * Email" %>
<br><br>
<%= f.text_area :user_message, :required => true, :class => "message_user-message_input", :placeholder => " * Write a message" %><br><br>
<%= f.text_field :captcha, :required => true, :name => "captcha", :class => "message_input_default", :placeholder => " * #{#a} + #{#b} = ?" %><br><br>
<div id="RecaptchaField2"></div>
<%= f.submit "Send", :class => "messages_submit_button" %>
<% end %>
Pages Controller
class PagesController < ApplicationController
def index
#message = Message.new
#a = rand(9)
#b = rand(9)
session["sum"] = #a + #b
end
end
Messages Controller
class MessagesController < ApplicationController
def show
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
if params["captcha"].to_i == session["sum"] && #message.save!
UserMailer.welcome_email(#message).deliver_now
redirect_to '/message_sent'
else
redirect_to '/'
end
end
private
def message_params
return params.require(:message).permit(:first_name, :last_name, :email, :user_message, :captcha)
end
end
Messages Migration
class CreateMessages < ActiveRecord::Migration
def change
create_table :messages do |t|
t.string :captcha
t.string :first_name
t.string :last_name
t.string :email
t.string :user_message
t.timestamps null: false
end
end
end
Schema
ActiveRecord::Schema.define(version: 20150822040444) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "messages", force: :cascade do |t|
t.string "captcha"
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "user_message"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
Routes
Rails.application.routes.draw do
resources :pages
resources :messages
resources :admins
get '/' => 'pages#index'
get '/new' => 'messages#new'
post '/message_sent' => 'messages#create'
get '/message_sent' => 'messages#show'
end
EDITED Attempted this code, but instead of saving 4 elements, it executes the "else" statement and redirects as if it is not being saved at all.
Messages Controller
class MessagesController < ApplicationController
def show
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
if params[:message][:captcha].to_i == session["sum"] && #message.save!
UserMailer.welcome_email(#message).deliver_now
redirect_to '/message_sent'
else
redirect_to '/'
end
end
private
def message_params
return params.require(:message).permit(:first_name, :last_name, :email, :user_message, :captcha)
end
end
Remove name attribute from here:
<%= f.text_field :captcha, :required => true, :name => "captcha", :class => "message_input_default", :placeholder => " * #{#a} + #{#b} = ?" %><br><br>
It happens because name parameter is generated by rails itself, and it's responsible to structure your query. Thus this erb line:
<%= f.text_field :first_name %>
Will generate this html:
<input type="text" name="message[first_name]">
And when you submit form it will produce query like this
{ message: { first_name: 'value_of_input' } }
But you provided custom name that overridden default behaviour and produces requests like this:
{ captcha: 'captcha_val', message: { first_name: 'some_val1', last_name: 'some_val2', ... } }
Then you extract message params from params:
def message_params
params.
require(:message).
permit(:first_name, :last_name, :email, :user_message, :captcha)
end
Finally you create message with this hash:
{ first_name: .., last_name: .., email: .., user_message: .. }

Resources