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.
Related
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)
I'm trying to figure out shallow nesting in Rails but I get RecordNotFound for certain actions. A student has many checklists, a checklist belongs to a student, and I made sure routes.rb was setup correctly and form_with partials were getting both the student and checklist passed in.
I think something in my controller is messed up:
class ChecklistsController < ApplicationController
before_action :get_student
before_action :set_checklist, only: %i[show edit update destroy]
def index
#checklists = #student.checklists
end
def show
#student = #checklist.student
end
def new
#checklist = #student.checklists.build
end
def edit
#student = #checklist.student
end
def create
#checklist = #student.checklists.build(checklist_params)
if #checklist.save
redirect_to #checklist, notice: 'Checklist was successfully created.'
else
render :new, status: :unprocessable_entity
end
end
def update
#student = #checklist.student
if #checklist.update(checklist_params)
redirect_to #checklist, notice: 'Checklist was successfully updated.'
else
render :edit, status: :unprocessable_entity
end
end
def destroy
#student = #checklist.student
#checklist.destroy
redirect_to student_checklists_url(#student), notice: 'Checklist was successfully destroyed.'
end
private
def set_checklist
#checklist = #student.checklists.find(params[:id])
end
def get_student
#student = Student.find(params[:student_id])
end
# Only allow a list of trusted parameters through.
def checklist_params
params.require(:checklist).permit(:title, :date, :setting)
end
end
When using shallow nesting you need to separate the callbacks for the collection actions (new, create, index) which are nested from the member actions (show, edit, update, destroy) which are not:
class ChecklistsController < ApplicationController
before_action :set_student, only: %i[new, index, create]
before_action :set_checklist, only: %i[show edit update destroy]
def index
#checklists = #student.checklists
end
# Defining this empty method is actually optional - Rails will implicitly render `show.html.erb` anyways
def show
end
def new
#checklist = #student.checklists.build
end
def create
#checklist = #student.checklists.build(checklist_params)
if #checklist.save
redirect_to #checklist, notice: 'Checklist was successfully created.'
else
render :new, status: :unprocessable_entity
end
end
def edit
end
def update
if #checklist.update(checklist_params)
redirect_to #checklist, notice: 'Checklist was successfully updated.'
else
render :edit, status: :unprocessable_entity
end
end
def destroy
#checklist.destroy
redirect_to student_checklists_url(#student), notice: 'Checklist was successfully destroyed.'
end
private
def set_student
#student = Student.find(params[:student_id])
end
def set_checklist
# this lookup will never be based off a student record
# since the route is not nested
#checklist = Checklist.eager_load(:student)
.find(params[:id])
#student = #checklist.student
end
# Only allow a list of trusted parameters through.
def checklist_params
params.require(:checklist)
.permit(:title, :date, :setting)
end
end
notes use rails 5.2 and postgresql
I have Foluser model contains name,email,password,id_watch
I need when admin add new foluser
generate password
when admin create new foluser generate password like Secure Password Generator
get id_watch from admin model and put it to id_watch from Foluser model
Adminwhen register enterusername,email,password,id_watch`
in point 2 need take this id_watch and save it in user model .
admin only create foluser
`
class FolusersController < ApplicationController
before_action :set_foluser, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show, :new , :create, :edit]
# GET /folusers
# GET /folusers.json
def index
#folusers = current_master.foluser.all
#render json: #folusers
end
# GET /folusers/1
# GET /folusers/1.json
def show
##folusers = Foluser.where(master_id: #master.id).order("created_at DESC")
##foluser = Foluser.find(params[:id])
#render json: #foluser
end
# GET /folusers/new
def new
#foluser = current_master.foluser.build
end
# GET /folusers/1/edit
def edit
#render json: #foluser
end
# POST /folusers
# POST /folusers.json
def create
#foluser = current_master.foluser.build(foluser_params)
respond_to do |format|
if #foluser.save
format.html { redirect_to #foluser, notice: 'Foluser was successfully created.' }
format.json { render :show, status: :created, location: #foluser }
else
format.html { render :new }
format.json { render json: #foluser.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /folusers/1
# PATCH/PUT /folusers/1.json
def update
respond_to do |format|
if #foluser.update(foluser_params)
format.html { redirect_to #foluser, notice: 'Foluser was successfully updated.' }
format.json { render :show, status: :ok, location: #foluser }
else
format.html { render :edit }
format.json { render json: #foluser.errors, status: :unprocessable_entity }
end
end
end
# DELETE /folusers/1
# DELETE /folusers/1.json
def destroy
#foluser.destroy
respond_to do |format|
format.html { redirect_to folusers_url, notice: 'Foluser was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_foluser
#foluser = Foluser.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def foluser_params
params.require(:foluser).permit(:name, :email, :numberphone, :password)
end
end
foluser model
class Foluser < ApplicationRecord
belongs_to :admin, :optional => true
end
admin model
class Master < ApplicationRecord
has_many :foluser
end
Using your current code, setting the id_watch can be done here in the controller:
class FolusersController < ApplicationController
def create
#foluser = current_master.folusers.build(foluser_params)
#foluser.id_watch = current_master.id_watch # <-- !!!
respond_to do |format|
if #foluser.save
# ...
end
end
end
end
Despite our extended conversation above, I'm still unclear what you're trying to achieve with the "password generation".
(Should it be generated in the front-end, or the back-end? Should it be stored encrypted, or in plain text? If encrypted, do you need to be able to reverse this encryption? Is it a "permanent" password, or a "temporary" password? ...)
Therefore, the following code should be taken with a big pinch of salt - since I still don't really know what the desired/correct behaviour is.
In the FolusersController, you've defined the following method:
def foluser_params
params.require(:foluser).permit(:name, :email, :numberphone, :password)
end
However, if you want the password to be generated by the server then you shouldn't be allowing the admin to set the password through the controller. Therefore, remove this parameter:
def foluser_params
params.require(:foluser).permit(:name, :email, :numberphone)
end
And then somewhere - perhaps in the controller, or as a hook in the model - set this password to something random:
class FolusersController < ApplicationController
def create
#foluser = current_master.folusers.build(foluser_params)
#foluser.password = SecureRandom.hex(10 + rand(6))
# ...
end
end
# or
class Foluser < ApplicationRecord
after_initialize :default_password
def default_password
self.password ||= SecureRandom.hex(10 + rand(6))
end
end
I think you found the solution, use rails callbacks in your model to extract this kind of logic from the controller.
But I'd rather use after_initialize than before_save so that you won't set a default password before each save(so possibly even update action)
Then use things like SecureRandom (ActiveSupport concern) (already bundled by rails, no requires required)
after_initialize :defaultpassword
...
def default_password
self.password ||= SecureRandom.hex(10 + rand(6))
end
not the best way to do random I know but feel free to customize it.
secure_random output examples:
=>bf8d42b174d297f6460eef
=>efd28869171a1ec89c3438
=>3855c61fb6b90ed549d777
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
I'm trying to develop a app in Ruby on Rails 4.0 (already used older versions of this incredible framework) and I having some troubles.
I installed the FriendlyID gem and I think everything is okay, but I'm receiving errors when I try to test my app.
If I go to http://0.0.0.0:3000/categories/1, this works. But when I click in "edit" in this page, or just go to http://0.0.0.0:3000/categories/electronics (that's the slugged name of category with ID 1), I receive the following error:
Couldn't find Category with id=electronics
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id]) #Here's pointed the error
end
Category Model:
class Category < ActiveRecord::Base
extend FriendlyId
friendly_id :name, use: :slugged
# Validations
validates_uniqueness_of :name, :case_sensitive => false
end
Category Controller:
(generated by scaffold for test purposes)
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :edit, :update, :destroy]
# GET /categories
# GET /categories.json
def index
#categories = Category.all
end
# GET /categories/1
# GET /categories/1.json
def show
end
# GET /categories/new
def new
#category = Category.new
end
# GET /categories/1/edit
def edit
end
# POST /categories
# POST /categories.json
def create
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to #category, notice: 'Category was successfully created.' }
format.json { render action: 'show', status: :created, location: #category }
else
format.html { render action: 'new' }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /categories/1
# PATCH/PUT /categories/1.json
def update
respond_to do |format|
if #category.update(category_params)
format.html { redirect_to #category, notice: 'Category was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
# DELETE /categories/1
# DELETE /categories/1.json
def destroy
#category.destroy
respond_to do |format|
format.html { redirect_to categories_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def category_params
params.require(:category).permit(:name)
end
end
Migration:##
(I added friendlyId after create the Category table, but I think is okay)
class AddColumnToCategory < ActiveRecord::Migration
def change
add_column :categories, :slug, :string
add_index :categories, :slug, unique: true
end
end
Routes:
resources :categories
Hope you can help me. What I'm doing wrong in Rails 4.0?
Check the doc, friendly id stopped hacking find method (for the greater good), you now have to do:
# Change Category.find to Category.friendly.find in your controller
Category.friendly.find(params[:id])
You can now use:
extend FriendlyId
friendly_id :name, use: [:finders]
in your model.