Rails 4.2 : Form with multiple models - param is missing or the value - ruby

I'm having trouble with Rails 4.2 to create a form with multiple models.
I'm creating a form to allow a user to order a gift card with a custom stripe payment form all in one.
I tried different ways using form_tag instead of simple_form_for and simple_fields_for and I tried all the solution provided on this website but I can't find a way out of this hell!
My form is the following :
=simple_form_for #giftcard, url: gift_cards_path, html: {"accept-charset" => "UTF-8", :autocomplete => "off", :enctype => "multipart/form-data", :method => "post" } do |f|
(...)
= field_set_tag 'Delivery mode' do
.form-row
= f.label :delivery_mode, 'She receive the mail'
= f.radio_button :delivery_mode, 'email_to_recipient'
= f.label :delivery_mode, 'I receive the mail'
= f.radio_button :delivery_mode, 'email_to_giver'
= f.label :delivery_mode, 'Delivery with in box with a jewel'
= f.radio_button :delivery_mode, 'gift_box', id: 'gift_box'
= field_set_tag 'Who is the gift for ?' do
.form-row
= f.input :recipient_first_name, label: 'First Name'
.form-row
= f.input :recipient_last_name, label: 'Last Name'
.form-row
= f.input :recipient_email, placeholder: 'example#mail.com', label: 'Son adresse email'
.form-row
= f.input :message, placeholder: 'Your message', label: 'Son message'
= f.simple_fields_for :payment do |p|
.form-row
= p.input :card_number, label: 'Numéro de carte'
.form-row
= p.input :card_cvc, input_html: { "size" => 4, "data-stripe" => "cvv" }, label: 'CVV'
.form-row
= p.input :card_expiration_month, input_html: { "placeholder" => "MM", "size" => 2, "data-stripe" => "exp-month" }
= p.input :card_expiration_year, input_html: { "placeholder" => "YYYY", "size" => 4, "data-stripe" => "exp-year" }
.form-row
= f.button :submit, 'Send your gift !'
My controller is the following :
def new
#giftcard = GiftCard.new
#payment = Payment.new
end
def create
#giftcard = GiftCard.new(giftcard_params)
#payment = Payment.new(creditcard_params)
#giftcard.amount += 9.90 if #giftcard.gift_box?
respond_to do |format|
if #giftcard.save && #payment.process_payment
code_coupon = CodeCoupon.create(name: giftcard.coupon, value: 0, category: 'membership', origin: 'gift')
if giftcard.delivery_mode == 'gift_box'
UserMailer.prepare_gift_box(#giftcard)
UserMailer.giftcard_recipe(#giftcard)
elsif #giftcard.delivery_mode == 'email_to_giver'
UserMailer.send_gift_card(#giftcard, #giftcard.giver_email)
UserMailer.giftcard_recipe(#giftcard)
elsif #giftcard.delivery_mode == 'email_to_recipient'
UserMailer.send_gift_card(#giftcard, #giftcard.recipient_email)
UserMailer.giftcard_recipe(#giftcard)
end
format.html { redirect_to #giftcard, notice: 'Votre carte cadeau à bien été créée et vous a été envoyé par email' }
format.json { render :show, status: :created, location: #giftcard }
else
format.html { render :new, locals: { errors: #giftcard.errors.full_messages } }
format.json { render json: #giftcard.errors, status: :unprocessable_entity }
end
end
end
private
def giftcard_params
params.require(:gift_card).permit(:recipient_email, :recipient_first_name, :recipient_last_name, :giver_email, :giver_phone, :giver_first_name, :giver_last_name, :message, :amount, :delivery_mode, :delivery_first_name, :delivery_last_name, :delivery_street, :delivery_city, :delivery_zip)
end
def creditcard_params
params.require(:payment).permit(:card_number, :card_cvc, :card_expiration_month, :card_expiration_year, :card_token )
end
And the troubled model:
class Payment
include ActiveModel::Model
attr_accessor :card_number, :card_cvc, :card_expiration_month, :card_expiration_year, :card_token
validates :card_number, presence: true
validates :card_cvc, presence: true
validates :card_expiration_month, presence: true
validates :card_expiration_year, presence: true
def payment_process
Stripe::Charge.create(
amount: amount * 100,
description: "paiement unique",
source: card_token,
currency: 'eur'
)
end
end
When I try to validate the form, it returns the following error :
ActionController::ParameterMissing - param is missing or the value is empty: payment:
actionpack (4.2.8) lib/action_controller/metal/strong_parameters.rb:251:in require'
app/controllers/gift_cards_controller.rb:56:increditcard_params'
app/controllers/gift_cards_controller.rb:13:in `create'
If I remove the require in the creditcard_params method and I click on submit, I get in the log :
Unpermitted parameter: payment
Unpermitted parameters: utf8, authenticity_token, gift_card, commit
(0.1ms) BEGIN
(0.2ms) ROLLBACK
EDIT
Here the parameters that I receive in the log :
Started POST "/gift_cards" for ::1 at 2017-10-06 10:17:42 +0200
Processing by GiftCardsController#create as HTML
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"UB1keTN7YNDhaEBdIT6cYf/qrwr/QxCpFEYwvGDBLWmYvZiVjXxFg+bQ9vaPAfQTx32d/D7jHnShsTmsqMwLrA==",
"gift_card"=>{
"recipient_first_name"=>"",
"recipient_last_name"=>"",
"recipient_email"=>"",
"message"=>"",
"giver_first_name"=>"",
"giver_last_name"=>"",
"giver_email"=>"",
"giver_phone"=>"",
"delivery_first_name"=>"",
"delivery_last_name"=>"",
"delivery_street"=>"",
"delivery_city"=>"",
"delivery_zip"=>"",
"payment"=>{
"card_number"=>"",
"card_cvc"=>"",
"card_expiration_month"=>"",
"card_expiration_year"=>""
}
},
"commit"=>"Send your gift !"
}
Thank you in advance for your help,
Regards

In my opinion, one way of achieving this will be, changes in person_params as below
def person_params
params.require(:gift_card).permit(:recipient_email, :recipient_first_name, :recipient_last_name, :giver_email, :giver_phone, :giver_first_name, :giver_last_name, :message, :amount, :delivery_mode, :delivery_first_name, :delivery_last_name, :delivery_street, :delivery_city, :delivery_zip, payment: [:card_number, :card_cvc, :card_expiration_month, :card_expiration_year])
end
This will whitelist all your parameters as you have shown in params,
Once this is done, further you will have to change your create action as
#payment = Payment.new(person_params(params)[:payment])
instead of your code.
Addition to this there is a code change in if condition as per the model you have shown #giftcard.save && #payment.payment_process.
The complete solution will be as below:
def create
#giftcard = GiftCard.new(giftcard_params)
#payment = Payment.new(giftcard_params[:payment])
#giftcard.amount += 9.90 if #giftcard.gift_box?
respond_to do |format|
if #giftcard.save && #payment.payment_process
code_coupon = CodeCoupon.create(name: giftcard.coupon, value: 0, category: 'membership', origin: 'gift')
if giftcard.delivery_mode == 'gift_box'
UserMailer.prepare_gift_box(#giftcard)
UserMailer.giftcard_recipe(#giftcard)
elsif #giftcard.delivery_mode == 'email_to_giver'
UserMailer.send_gift_card(#giftcard, #giftcard.giver_email)
UserMailer.giftcard_recipe(#giftcard)
elsif #giftcard.delivery_mode == 'email_to_recipient'
UserMailer.send_gift_card(#giftcard, #giftcard.recipient_email)
UserMailer.giftcard_recipe(#giftcard)
end
format.html { redirect_to #giftcard, notice: 'Votre carte cadeau à bien été créée et vous a été envoyé par email' }
format.json { render :show, status: :created, location: #giftcard }
else
format.html { render :new, locals: { errors: #giftcard.errors.full_messages } }
format.json { render json: #giftcard.errors, status: :unprocessable_entity }
end
end
end
private
def giftcard_params
params.require(:gift_card).permit(:recipient_email, :recipient_first_name, :recipient_last_name, :giver_email, :giver_phone, :giver_first_name, :giver_last_name, :message, :amount, :delivery_mode, :delivery_first_name, :delivery_last_name, :delivery_street, :delivery_city, :delivery_zip, payment: [:card_number, :card_cvc, :card_expiration_month, :card_expiration_year])
end
end

Related

Postman problems in post request

I'm trying to use postman with a post request for mi controller "comments". This rquest show me the following error:
"NoMethodError (undefined method `news'..."
Here is the comment model:
class Comment < ApplicationRecord
include Discard::Model
belongs_to :user, optional: true
belongs_to :news, optional: true
validates :news_id, presence: true
validates :user_id, presence: true
validates :body, presence: true
end
and here is the controller:
module Api
module V1
class CommentsController < ApplicationController
before_action :authenticate_request, only: %i[index create update destroy]
before_action :set_comment, only: %i[update destroy]
before_action :authorize_user, only: %i[show create update destroy]
def index
#comment = Comment.order('created_at DESC')
render json: CommentSerializer.new(#comment,
fields: { comment: :body })
.serializable_hash, status: :ok
end
def create
#comment = Comment.new(comment_params)
#comment.user = #current_user
#comment.news = #current_user.news.find(params[:news_id])
if #comment.save
render json: CommentsSerializer.new(#comment).serializable_hash, status: :created
else
render_error
end
end
def update
if ownership?
#comment = Comment.update(comment_params)
render json: CommentSerializer.new(#comment).serializable_hash
else
render json: #comment.errors, status: :unprocessable_entity
end
end
def destroy
if ownership?
#comment.discard
head :no_content
else
render json: { error: 'unauthorized' }, status: :unauthorized
end
end
private
def set_comment
#comment = Comment.find(params[:id])
end
def comment_params
params.require(:comment).permit(:body)
end
def render_error
render json: { errors: #comment.errors.full_messages },
status: :unprocessable_entity
end
def render_unauthorized
render status: :unauthorized, json: {
errors: [I18n.t('errors.controllers.unauthorized')]
}
end
end
end
end
When I send a request for post in postman, it show the following problem:
NoMethodError (undefined method `news' for #<User id: 27, first_name: "rafa", last_name: "quinteros", email: "rafa4#email.com", password_digest: [FILTERED], photo: nil, role_id: 1, created_at: "2022-08-05 13:42:51.360055000 -0300", updated_at: "2022-08-05 13:42:51.360055000 -0300", discarded_at: nil>):
Well, your comment.user receives #current_user, but the user doesn't have news method/relationship. You should write a news method to stop this error.

while population sub category dropdown receive below error active admin

Error:-
ActionView::MissingTemplate (Missing template admin/blogs/get_child_category, active_admin/resource/get_child_category, active_admin/base/get_child_category, inherited_resources/base/get_child_category, application/get_child_category with {:locale=>[:en], :formats=>[:html, :text, :js, :css, :ics, :csv, :vcf, :vtt, :png, :jpeg, :gif, :bmp, :tiff, :svg, :mpeg, :mp3, :ogg, :m4a, :webm, :mp4, :otf, :ttf, :woff, :woff2, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip, :gzip], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :arb, :jbuilder]}. Searched in:
* "/home/rakesh/Documents/codetoart-website/app/views"
admin/category.rb
form do |f|
f.inputs do
.....
f.input :Category,:input_html => {
:onchange => remote_request(:post, :get_child_category, {:child_category_id=>"$('#blog_category_id').val()"}, :child_category_id)
}
f.input :child_category_id
.....
end
f.actions
end
method:-
controller do
def get_child_category
#child_category = Category.where(:parent_id => params[:child_category_id])
render :text=>view_context.options_from_collection_for_select(#child_category, :id, :name)
end
end
application_helper.rb
def remote_request(type, path, params={}, target_tag_id)
"$.#{type}('#{path}',
{#{params.collect { |p| "#{p[0]}: #{p[1]}" }.join(", ")}},
function(data) {$('##{target_tag_id}').html(data);}
);"
end
is there any solution?
as it's not population sub category dropdown.

rails 5 strong params updating record sets other columns to nil

For some reason, when I submit my form and update my user profile record, my user profile records have all the other columns updated to nil for some reason.
Lets say User.last.user_profile has an attribute "linkedin_url" and it is set to "www.yahoo.com". Once I submit the form, the User :phone number, and UserProfile :work_address, :work_zipcode gets updated, but the "linkedin_url" gets set to nil. IDK why!
class UserProfilesController < ApplicationController
def update
#user = User.last
if #user.update(user_profile_params)
respond_to do |format|
format.html {
redirect_to user_profile_path(#user)
}
format.json {
render :show, status: :ok, location: #preference
}
end
end
end
def user_profile_params
params.require(:user).permit( :phone_number, user_profile_attributes: [:work_address, :work_zipcode])
end
form
= form_for #user, url: user_profile_path(#user), method: :put do |f|
= f.fields_for :user_profile do |ff|
= ff.label :work_address
%br
= ff.text_field :work_address
%br
= ff.label :work_zipcode
%br
= ff.text_field :work_zipcode
%br
= f.label :phone_number
%br
= f.text_field :phone_number
%br
= f.submit "Submit", class: "btn"
def user_profile_params
params.require(:user).permit(
:phone_number,
user_profile_attributes: [:work_address, :work_zipcode] # ⇐ HERE
)
end
In the method above you should explicitly list :linkedin_url:
def user_profile_params
params.require(:user).permit(
:phone_number,
user_profile_attributes: [:work_address, :work_zipcode, :linkedin_url]
)
end
Just solved my own problem, it was because i didn't whitelist :id in the strong parameters.

Uploading image in paperclip lags my server for 3 minutes and then gives me error

This is my controller
class PinsController < ApplicationController
before_action :authenticate_user!, except: [:index]
before_action :set_pin, only: [:show, :edit, :update, :destroy]
# GET /pins
# GET /pins.json
def index
#pins = Pin.all
end
# GET /pins/1
# GET /pins/1.json
def show
end
# GET /pins/new
def new
#pin = current_user.pins.new
end
# GET /pins/1/edit
def edit
#pin = current_user.pins.find(params[:id])
end
# POST /pins
# POST /pins.json
def create
#pin = current_user.pins.new(pin_params)
respond_to do |format|
if #pin.save
format.html { redirect_to #pin, notice: 'Pin was successfully created.' }
format.json { render :show, status: :created, location: #pin }
else
format.html { render :new }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /pins/1
# PATCH/PUT /pins/1.json
def update
#pin = current_user.pins.find(params[:id])
respond_to do |format|
if #pin.update(pin_params)
format.html { redirect_to #pin, notice: 'Pin was successfully updated.' }
format.json { render :show, status: :ok, location: #pin }
else
format.html { render :edit }
format.json { render json: #pin.errors, status: :unprocessable_entity }
end
end
end
# DELETE /pins/1
# DELETE /pins/1.json
def destroy
#pin = current_user.pins.find(params[:id])
#pin.destroy
respond_to do |format|
format.html { redirect_to pins_url, notice: 'Pin was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_pin
#pin = Pin.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def pin_params
params.require(:pin).permit(:description, :image)
end
end
This is my model
class Pin < ActiveRecord::Base
attr_accessible :description, :image
has_attached_file :image, styles: { medium: "320x240>"}
validates :description, presence: true
validates :user_id, presence: true
validates_attachment :image, presence: true,
content_type: { content_type: ["image/jpeg", "image/jpg", "image/gif", "image/png"] },
size: { in: 0..5.megabytes }
belongs_to :user
end
When I try to upload an image, my server lags for 3 minutes, console goes crazy and after those 3 minutes I get this error message - "has contents that are not what they are reported to be".
I just changed the model to this
class Pin < ActiveRecord::Base
attr_accessible :description, :image
has_attached_file :image, styles: { medium: "320x240>"}
validates :description, presence: true
validates :user_id, presence: true
validates_attachment :image, presence: true,
# content_type: { content_type: ["image/jpeg", "image/jpg", "image/gif", "image/png"] },
size: { in: 0..5.megabytes }
validates_attachment_content_type :image, :content_type => /\Aimage/
belongs_to :user
end

Undefined method on staging environment, works fine locally

Having some issues with my staging environment at the moment. I have my app on Heroku (both staging and production). It works perfectly on local, but when I push it to the staging environment I keep getting an undefined method for category_id.
I have reset the databases, run my migrations and put the seeds in to no avail. The only thing I can think is there is something wrong with my product model but I haven't changed that part of the app since I last pushed it to production (works fine with the current version on there).
Is there any chance that one of my migrations is not going through? That's the only thing I can think of.
Product model:
class Product < ActiveRecord::Base
belongs_to :subcategory
mount_uploader :product_image, ProductImageUploader
validates :title, :description, presence: true
validates :title, uniqueness: true
validates :image_url, allow_blank: true, format: { with: %r{\.(gif|jpg|png)\Z}i, message: 'must be a URL for GIF, JPG or PNG image.'}
validates :subcategory_id, presence: true
end
Products Controller:
class ProductsController < ApplicationController
skip_before_filter :authorize, only: [:show, :index]
before_action :set_product, only: [:show, :edit, :update, :destroy]
# GET /products
# GET /products.json
def index
#products = Product.order("title ASC")
#categories = Category.all
#subcategories = Subcategory.order("title ASC")
end
# GET /products/1
# GET /products/1.json
def show
end
# GET /products/new
def new
#product = Product.new
end
# GET /products/1/edit
def edit
end
# POST /products
# POST /products.json
def create
#product = Product.new(product_params)
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
format.html { render action: 'new' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /products/1
# PATCH/PUT /products/1.json
def update
respond_to do |format|
if #product.update(product_params)
format.html { redirect_to #product, notice: 'Product was successfully updated.' }
format.json { head :ok }
else
format.html { render action: 'edit' }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
# DELETE /products/1
# DELETE /products/1.json
def destroy
#product.destroy
respond_to do |format|
format.html { redirect_to products_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :description, :image_url, :product_image, :subcategory_id, :category_id)
end
end
The view that is causing the error message:
=form_for(#product) do |f|
-if #product.errors.any?
#error_explanation
%h2
=pluralize(#product.errors.count, "error")
prohibited this product from being saved:
%ul
-#product.errors.full_messages.each do |msg|
%li
=msg
%br
.field
=f.label :title
%br
=f.text_field :title, size: 100
%br
.field
=f.label :description
%br
=f.text_area :description, cols: 100, rows: 10
%br
.field
=f.label :product_image
=f.file_field :product_image
.field
=f.label :category_id
%br
=f.collection_select(:category_id, Category.all, :id, :title)
%br
.field
=f.label :subcategory_id
%br
// =f.collection_select(:subcategory_id, Subcategory.all, :id, :title)
%select{:id => "product_subcategory_id", :name => "product[subcategory_id]", :disabled => "disabled"}
%option
Select a category first...
%br
.actions
%br
=f.submit
%br
%br
:javascript
$(document).ready(function(){
$("select#product_category_id").change(function(e) {
var val = $(this).val();
var subCatSelect = $("select#product_subcategory_id");
subCatSelect.empty();
subCatSelect.append("<option>Loading...</option>");
$.get("/subcategories.json?category="+val)
.done(function(response) {
subCatSelect.empty();
if (response.length > 0) {
$.each(response, function(k,v) {
subCatSelect.append("<option id='"+v.id+"'>"+v.title+"</option>");
subCatSelect.removeAttr("disabled");
});
} else {
subCatSelect.attr("disabled", "disabled");
subCatSelect.append("<option>No Subcategories</option>");
}
});
});
});
And the error message:
ActionView::Template::Error (undefined method `category_id' for #<Product:0x007f64ab47c1d0>):
30: .field
31: =f.label :category_id
32: %br
33: =f.collection_select(:category_id, Category.all, :id, :title)
app/views/products/_form.html.haml:33:in `block in _app_views_products__form_html_haml__3508934121535598535_70035173692040'
app/views/products/_form.html.haml:1:in `_app_views_products__form_html_haml__3508934121535598535_70035173692040'
app/views/products/new.html.haml:7:in `_app_views_products_new_html_haml__3953831312052620477_70035173605140'
It may be an issue with the naming conventions in your asset pipeline.
Try precompiling your asset pipeline befor pushing to Heroku:
bundle exec rake assets:precompile RAILS_ENV=production
git commit -a -m "Prempile assets for release"
git push
git push heroku master
Here's some more info from Heroku on this:
https://devcenter.heroku.com/articles/rails-asset-pipeline
Not sure if this will fix it, but it's very easy to try it. I've found that this fixes most of problems moving from development/test to production.
Hope this helps!
I'm not too sure what happened but when I cleared the heroku DB, re-ran my migrations and seeds it decided to work.... I have no idea what happened.

Resources