Active Model Forbidden attributes error - ruby-on-rails

would someone be able to help me understand this error. I am trying to create a contact form in rails following the building web apps tutorial. I followed the steps to generate a message scaffold. I then amended my routes. Next it said to put this into the messages controller show action.
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
I have done this and i am getting the following error
ActiveModel::ForbiddenAttributesError in MessagesController#create
ActiveModel::ForbiddenAttributesError
This is my message controller file
class MessagesController < InheritedResources::Base
def show
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
end
end
end
My routes file is as follows
# devise_for :users
resources :products do
resources :orders, only: [:new, :create]
#tells rails needs product id number
end
# get 'pages/payment'
get 'home/about'
get 'messages/new'
get 'seller' => "products#seller"
get 'sales' => "orders#sales"
get 'static_pages/productlanding'
get "content/veg"
get "content/fruit"
get "content/mix"
get 'subscriptions/new'
root 'static_pages#home'

Why are you saving in the show action?
--
Params
The ForbiddenAttributes error stems from the strong_params functionality of Rails.
When saving data, you're meant to pass the params through to your model through a strong_params method. This is typically achieved with the following setup:
#app/controllers/messages_controller.rb
class MessagesController < ApplicationController
def show
#message = Message.find(params[:id])
end
def new
#message = Message.new
end
def create
#message = Message.new(message_params)
#message.save
end
private
def message_params
params.require(:message).permit(:your, :message, :params)
end
end
This is how your controller should really be constructed. Your error, I believe, is caused by your lack of params to pass through to the attributes in your model (hence your call to #save resulting in trying to populate your model with non-data).

Strange. You execute saving method in "show" method of controller which responsible for showing up the content on the separate page.
You should replace as following:
def create
if #message.save
flash[:notice] = 'Thanks for Your Message'
format.html { redirect_to root_path }
end
end

i have managed to sort this with the following! Thanks for all the help
class MessagesController < ApplicationController
before_action :set_message, only: [:show, :edit, :update, :destroy]
# GET /messages
# GET /messages.json
def index
#messages = Message.all
end
# GET /messages/1
# GET /messages/1.json
def show
end
# GET /messages/new
def new
#message = Message.new
end
# GET /messages/1/edit
def edit
end
# POST /messages
# POST /messages.json
def create
#message = Message.new(message_params)
respond_to do |format|
if #message.save
flash.now[:notice] = 'Thank you for your message!'
format.html { redirect_to root_path }
format.json { render :show, status: :created, location: #message }
else
format.html { render :new }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /messages/1
# PATCH/PUT /messages/1.json
def update
respond_to do |format|
if #message.update(message_params)
format.html { redirect_to #message, notice: 'Message was successfully updated.' }
format.json { render :show, status: :ok, location: #message }
else
format.html { render :edit }
format.json { render json: #message.errors, status: :unprocessable_entity }
end
end
end
# DELETE /messages/1
# DELETE /messages/1.json
def destroy
#message.destroy
respond_to do |format|
format.html { redirect_to messages_url, notice: 'Message was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_message
#message = Message.find(params[:id])
end
.
def message_params
params.require(:message).permit(:name, :email, :company, :phone, :subject, :body)
end
end

I was facing this same error. The fix was to make the params function name same as the root tag of the post json like below
Post json
{"jobseeker_certificate":{"id":-1,"name":"First Class Medical Certificate","institute":"GACA","attachment":null}}
In Controller i changed jobseeker_aircraft_type_ratings_params to jobseeker_certificate_params
def jobseeker_certificate_params
params.require(:jobseeker_certificate).permit(:aircraft, :total_time, :pilot_in_command,
:co_pilot, :rating_expiry_date, :from, :to, :jobseeker_id, :grade, :institute, :attachment, :name,
:from, :to, :jobseeker_id, :grade, :institute, :attachment, :name, :sector_id, :certificate_type,
:details, :certificate_type, :details)
end

Related

Redirect to a post with specific name from user input in Ruby on Rails?

I am a newbie in RoR, thus sorry for stupid question :(
I have a Game model, with a code string. There is a welcome/index view in my app with a simple form_to input. I wish to redirect user to a Game with a specific code after he submits the form.
I understand that I should somehow combine a .where method and redirect_to in Welcome_controller, but I just can't figure out how...
Welcome_controller.rb:
class WelcomeController < ApplicationController
def index
end
def redirect
redirect_to ?game with a code that equals :param from input?
end
end
Welcome/index:
<h1>Let's join the game!</h1>
<%= form_tag redirect_path do %>
<%= text_field_tag(:param) %>
<%= submit_tag("Search") %>
<% end %>
routes.rb:
Rails.application.routes.draw do
get 'welcome/index'
resources :games
get 'games/index'
root 'welcome#index'
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
game.rb:
class Game < ApplicationRecord
validates :name, :presence => true
end
games_controller:
PREFACE = ('A'..'Z').to_a << ?_
SUFFIX = ('0'..'9').to_a
PREFACE_SIZE = 2
SUFFIX_SIZE = 3
class GamesController < ApplicationController
before_action :set_game, only: %i[ show edit update destroy ]
# GET /games or /games.json
def index
#games = Game.all
end
# GET /games/1 or /games/1.json
def show
end
# GET /games/new
def new
#game = Game.new
#game.code = gen_name
end
def gen_name
PREFACE.sample(PREFACE_SIZE).join << SUFFIX.sample(SUFFIX_SIZE).join
end
# GET /games/1/edit
def edit
end
# POST /games or /games.json
def create
#game = Game.new(game_params)
respond_to do |format|
if #game.save
format.html { redirect_to game_url(#game), notice: "Game was successfully created." }
format.json { render :show, status: :created, location: #game }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /games/1 or /games/1.json
def update
respond_to do |format|
if #game.update(game_params)
format.html { redirect_to game_url(#game), notice: "Game was successfully updated." }
format.json { render :show, status: :ok, location: #game }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
# DELETE /games/1 or /games/1.json
def destroy
#game.destroy
respond_to do |format|
format.html { redirect_to games_url, notice: "Game was successfully destroyed." }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_game
#game = Game.find(params[:id])
end
# Only allow a list of trusted parameters through.
def game_params
params.require(:game).permit(:code, :name)
end
end
In config/routes.rb you have defined resources :games, which creates default paths for CRUD actions. For the show action, which you are trying to get here, it would lead to /games/:id and the helper method would be game_path. You can also check this by running rails routes -c games command in the app directory. It should return all paths for games_controller
In the before_action callback for GamesController#show action, you are finding a Game object using Game.find(params[:id]). :id parameter is what you need to pass to the path helper that I mentioned earlier for the action to fire properly, so the path to a specific game would look like game_path(id: game.id). This will then automatically get converted to params. Alternatively, you can just pass the game object to the path helper and it will do the job for you like this: game_path(game)
Now in the WelcomeController#redirect action, you get the game code in params from the form submit. You need to first find the game for the submitted code like this:
game = Game.find_by(code: params[:param])
This should work if the code is unique for each game. Now that you have the correct game record, all you need is to redirect to the path that I've mentioned eariler:
redirect_to game_path(game)

SMS messages not being sent using Twilio and Rails

I am trying to integrate Twilio and my rails application to send different text messages based on what option is chosen and saved to the database in the form. However after studying the docs and viewing the example applications they provide (Send ETA Notifications), saving the completed form, no text message is sent and I cannot figure out why. I would love some suggestions
job_status are the options to choose from which the text message body needs to change with:
JOB_STATUSES = ["Wildey Que", "In Service-Bay", "Awaiting Approval",
"Awaiting Parts", "Jackson Collection Que", "Wildey Collection Que",
"Completed"]
message_sender.rb
class MessageSender
require 'twilio-ruby'
def self.send_message(job_id, host, to, message)
new.send_message(job_id, host, to, message)
end
def initialize
# To find TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN visit
# https://www.twilio.com/console
account_sid = ENV['---'] (These are entered)
auth_token = ENV['---']
#client = Twilio::REST::Client.new(account_sid, auth_token)
end
def send_message(job_id, host, to, message)
#client.messages.create(
from: twilio_number,
to: to,
body: message,
status_callback: "http://#{host}/jobs/#{job_id}"
)
end
private
def twilio_number
# A Twilio number you control - choose one from:
# https://www.twilio.com/console/phone-numbers/incoming
# Specify in E.164 format, e.g. "+16519998877"
ENV['+17652957305']
end
end
jobs_controller.rb
class JobsController < ApplicationController
before_action :set_job, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
# GET /jobs
# GET /jobs.json
def index
if(params.has_key? (:job_status))
#jobs = Job.where(job_status: params[:job_status]).order("created_at desc")
else
#jobs = Job.all.order("created_at desc")
end
end
# GET /jobs/1
# GET /jobs/1.json
def show
end
# GET /jobs/new
def new
#job = current_user.jobs.build
end
# GET /jobs/1/edit
def edit
end
#TWILLIO INITILIZATION
def send_initial_notification
#job.job_status = :Wildey_Que
if #job.save
message = 'Equip4you: Thanks for dropping your machine off, we will keep you updated here every step of the way'
notify(message)
else
redirect_with_error
end
end
def send_delivery_notification
#job.job_status = :Completed
if #job.save
message = 'Equip4you: Thank you for allowing us to take care of your machine for you, if you have any further questions or concerns feel free to contact 425-9999'
notify(message)
else
redirect_with_error
end
end
#END TWILLIO INIT
# POST /jobs
# POST /jobs.json
def create
#job = current_user.jobs.build(job_params)
respond_to do |format|
if #job.save
format.html { redirect_to #job, notice: 'Job was successfully created.' }
format.json { render :show, status: :created, location: #job }
else
format.html { render :new }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /jobs/1
# PATCH/PUT /jobs/1.json
def update
respond_to do |format|
if #job.update(job_params)
format.html { redirect_to #job, notice: 'Job was successfully updated.' }
format.json { render :show, status: :ok, location: #job }
else
format.html { render :edit }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jobs/1
# DELETE /jobs/1.json
def destroy
#job.destroy
respond_to do |format|
format.html { redirect_to jobs_url, notice: 'Job was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# TWILLIO INNIT
def notify(message)
MessageSender.send_message(
#job.id, request.host, #job.cell_number, message)
redirect_to jobs_url, notice: 'Message was delivered'
end
def redirect_with_error
message = "An error has occurred updating the ticket status"
redirect_to orders_url, flash: { error: message }
end
#TWILLIO INIT END
# Use callbacks to share common setup or constraints between actions.
def set_job
#job = Job.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def job_params
params.require(:job).permit(:job_status, :purchase_name, :contact_name, :cell_number, :home_number, :other_number, :other_number, :address, :machine_mod, :item_number, :serial_number, :concern, :accessories, :pickup_location, :paid, :invoice_number, :outcome, :avatar)
end
end
Routes.rb
require 'sidekiq/web'
Rails.application.routes.draw do
resources :jobs
devise_for :users
root to: 'jobs#index'
post '/jobs/new', to: 'jobs#new', as: 'initial_notifications'
post '/jobs/new', to: 'jobs#new', as: 'delivery_notifications'
routes.rb
require 'sidekiq/web'
Rails.application.routes.draw do
resources :jobs
devise_for :users
root to: 'jobs#index'
post '/jobs/new', to: 'jobs#new', as: 'initial_notifications'
post '/jobs/new', to: 'jobs#new', as: 'delivery_notifications'
Please check this def. It looks weird.
def twilio_number
# A Twilio number you control - choose one from:
# https://www.twilio.com/console/phone-numbers/incoming
# Specify in E.164 format, e.g. "+16519998877"
ENV['+17652957305']
end

Ruby-on-Rails NoMethodError in my controller undefined method `user_id' for nil:NilClass

My ruby application is throwing an error which has appeared all of a sudden. the error thrown is NoMethodError in JobsDevsController # listing=> undefined method `user_id' for nil:NilClass
The part of my code that throws this error in my controller is
def is_authorised
redirect_to root_path, alert: "You don't have permission..." unless current_user.id == #job.user_id
end
My Controller
class JobsDevsController < ApplicationController
before_action :set_jobs_dev , except: [:index, :new, :create, :show, :edit, :listing]
before_action :authenticate_user!, except: [:show, :listing]
before_action :is_authorised, only: [:listing, :budget, :description, :photo_upload, :location, :update, :show ]
# GET /jobs_devs
def index
#jobs_devs = JobsDev.all
end
# GET /jobs_devs/1
def show
end
# GET /jobs_devs/new
def new
#jobs_dev = current_user.jobs_devs.build
end
# def listing
# #jobs_dev = current_user.jobs_dev
# end
# GET /jobs_devs/1/edit
def edit
end
def budget
end
# POST /jobs_devs
def create
#jobs_dev = current_user.jobs_devs.build(jobs_dev_params)
if #jobs_dev.save!
redirect_to listing_jobs_dev_path(#jobs_dev), notice: 'Jobs dev was successfully created.'
else
render :new
end
end
# PATCH/PUT /jobs_devs/1
# def update
# if #jobs_dev.update(jobs_dev_params)
# redirect_to #jobs_dev, notice: 'Jobs dev was successfully updated.'
# else
# render :edit
# end
# end
def update
respond_to do |format|
if #jobs_dev.update(jobs_dev_params)
format.html { redirect_to #jobs_dev, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #jobs_dev }
else
format.html { render :edit }
format.json { render json: #jobs_dev.errors, status: :unprocessable_entity }
end
end
end
# DELETE /jobs_devs/1
def destroy
#jobs_dev.destroy
redirect_to jobs_devs_url, notice: 'Jobs dev was successfully destroyed.'
end
private
# Use callbacks to share common setup or constraints between actions.
def set_jobs_dev
#jobs_dev = JobsDev.find(params[:id])
end
def is_authorised
redirect_to root_path, alert: "You don't have permission..." unless current_user.id == #jobs_dev.user_id
end
# Only allow a trusted parameter "white list" through.
def jobs_dev_params
params.require(:jobs_dev).permit(:job_category, :job_type, :job_title, :job_description, :recurrence,
:budget, images: []
)
end
end
Please can you help with this senario
Make sure you set_job for listing actiton
You may need to add to the listing action directly
#job = current_user.job
or the better way to add it to before action of listing action and take order into consideration
Looks like your is_authorised method is looking for #job, which isn't set in your controller; rather, you assign #jobs_dev.
Update the method to the following:
def is_authorised
redirect_to root_path, alert: "You don't have permission..." unless current_user.id == #jobs_dev.user_id
end
I'm not sure that's sufficient, as you're skipping setting this in your before_action:
before_action :set_jobs_dev , except: [:index, :new, :create, :show, :edit, :listing]
It looks as if you'll need to remove :listing from the except clause there.
Try both of these things and it should work again. Let me know if you've any questions or have any issues with this :)

Basic rails crud in ajax with devise

I have a basic CRUD in rails and ajax, but I need to integrate Devise gem, when adding devise gem to my project and test the CRUD, I get this error:
the controller code in rails 4.2:
class ProductsController < ApplicationController
before_action :authenticate_user!
before_action :product_find, only: [:show, :update, :destroy, :edit]
def index
#products = Product.all.order('created_at DESC')
end
def show
end
def new
#product = Product.new
respond_to do |format|
format.html { render layout: false }
format.json { render json: #product }
format.js
end
end
def create
#product = current_user.products.build(product_params)
respond_to do |format|
if #product.save
format.json { render :show, status: :created, location: #product}
format.js
else
format.html { render :new }
format.json { render json: #product.errors, status: :unprocessable_entity }
format.js
end
end
end
def edit
end
def update
#product = Product.update(params[:id], product_params)
end
def destroy
#product.destroy
end
private
def product_find
#product = Product.where(id: params[:id]).first
end
def product_params
params.require(:product).permit(:name, :quantity, :price)
end
end
The user can connect without problems, the error occurs when I create a new product with the registered user
what am I doing wrong?
I think the error may be in the CREATE and NEW method
thank!
Have you set up the associations correctly for your models? The error undefined method 'products' for <User> suggests that you haven't.
# user.rb
has_many :products
# product.rb
belongs_to :user
Make sure you also have a user_id field on the Product model.

Rails association new_path error

I have two models post and topic in my rails app
class Post < ActiveRecord::Base
#relation between topics and post
belongs_to :topic
#post is valid only if it's associated with a topic:
validates :topic_id, :presence => true
#can also require that the referenced topic itself be valid
#in order for the post to be valid:
validates_associated :topic
end
And
class Topic < ActiveRecord::Base
#relation between topics and post
has_many :posts
end
I am trying to create association between both of them.
I want multiple post corresponding to each topic
I have used nested routes
Rails.application.routes.draw do
# nested routes
resources :topics do
resources :posts
end
resources :userdetails
devise_for :users, :controllers => { :registrations => "registrations" }
My Post controller looks like
class PostsController < ApplicationController
# before_action :set_post, only: [:show, :edit, :update, :destroy]
before_filter :has_userdetail_and_topic, :only =>[:new, :create]
# GET /posts
# GET /posts.json
#for new association SAAS book
protected
def has_userdetail_and_topic
unless(#topic =Topic.find_by_id(params[:topic_id]))
flash[:warning] = 'post must be for an existing topic'
end
end
public
def new
#post = #topic.posts.build
###topic = Topic.find(params[:topic_id1])
end
def index
#posts = Post.all
end
# GET /posts/1
# GET /posts/1.json
def show
end
# GET /posts/new
# GET /posts/1/edit
def edit
end
# POST /posts
# POST /posts.json
def create
##topic.posts << #post
##current_user = current_user.id
#current_user.posts << #topic.posts.build(params[:post])
##post = Post.new(post_params )
##post.userdetail_id = current_user.id
#Association functional between topic and post
#Class variable used
###topic.posts << #post
respond_to do |format|
if #post.save
format.html { redirect_to #post, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: #post }
else
format.html { render :new }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /posts/1
# PATCH/PUT /posts/1.json
def update
respond_to do |format|
if #post.update(post_params)
format.html { redirect_to #post, notice: 'Post was successfully updated.' }
format.json { render :show, status: :ok, location: #post }
else
format.html { render :edit }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end
# DELETE /posts/1
# DELETE /posts/1.json
def destroy
#post.destroy
respond_to do |format|
format.html { redirect_to posts_url, notice: 'Post was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:topic_id,:issue, :description, :rating, :userdetail_id)
end
end
I am trying to navigate from topics/index via code <td><%= link_to 'Write', new_topic_post_path(#topic) %> </td>
but when i try to go at localhost:3000/topics]
I am getting error
No route matches {:action=>"new", :controller=>"posts", :topic_id=>nil} missing required keys: [:topic_id]
Can any body tell me about this error, as i am new to rails please clearly specify answer.
And I have one more doubt, please tell me if i am doing association between topic and post incorrectly.I have confusion about this line of code -
#topic.posts << #post
What the error missing required keys: [:topic_id] is telling you is that you need to provide a hash with the key topic_id:
<%= link_to 'Write', new_topic_post_path(topic_id: #topic) %>
Passing a resource as to a route helper only works for the id param:
<%= link_to #topic, topic_path(#topic) %>
Is a kind of shorthand for:
<%= link_to #topic, topic_path(id: #topic.to_param) %>
Addition:
#prcu is also correct. The #topic record needs to be saved to the database. Records which are not saved do not have an id since the database assigns the id column when the record is inserted.
You also need to set the #topic instance variable in PostsController:
#topic = Topic.find(params[:id])
This is commonly done with a before filter:
before_filter :set_topic, only: [:new]
def set_topic
#topic = Topic.find(params[:id])
end
The same also need to be done in TopicsController#index.
#topic is not set or it's not persisted. You can not use topic not saved to db in this helper.

Resources