Group.find results in "Coudn't find Group with 'id'" - ruby-on-rails

Let me say something to begin with - I am very new to ruby on rails as a lot of users here are. So don't throw stones at me, please :)
I am trying to create an API application on Ruby for my android application. Here what I have a problem with:
user.rb Model
class User < ApplicationRecord
belongs_to :group
has_many :tasks
has_secure_password
end
And here is group.rb Model:
class Group < ApplicationRecord
has_many :users, dependent: :destroy
end
And UserController.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#group = Group.find(params.require(:user).permit(:group))
#user = User.new(user_params)
#group.users.create(#user)
#group.users.save
# #user.save!
render json: #user
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
where I want to create a new user.
I've already tried to create user with #user.create(user_params) but it says, that group doesn't exist, so now I am trying to do that via #group.users.create but exception ActiveRecord::RecordNotFound in UsersController#create keeps coming up, saying that it couldn't find Group with id={"id"=>1020};
The last thing I have to show is JSON that i send:
{
"group": {
"id":1020
},
"user": {
"name": "volkeee",
"email": "test#gmail.com",
"password": "123",
"repeat_password": "123"
}
}

Firstly create a new private method for group params like
def group_params
params.require(:group).permit(:id)
end
replace
#group = Group.find(params.require(:user).permit(:group))
with
#group_params = group_params
#group = Group.find(#group_params[:id])
I'm not in front of a PC so cant actually test. But this should work. Let me know if this doesn't.
A better approach
Replace
#user = User.new(user_params)
#group.users.create(#user)
#group.users.save
with
#user = #group.users.new(user_params)
#user.save
This is a much cleaner and rails way

Change your create method like below
def create
#group = Group.find_or_create_by(params[:group][:id]) do | group |
group.assign_attributes(group_params)
end
#user = #group.users.create(user_params)
render json: #user
end
create private method
def group_params
params.require(:group).permit(:id, :name, :has_subgroups, :created_at, :updated_at)
end
NOTE: user table should have group_id column

Related

Private Params Method not showing form data

So I am working on creating a playercard, which is basically a profile page for a user. The issue I am having on the backend is my private method playercard_params is only returning user_id, and not all the information inputted into the form...although regular params shows all the data needed to create the playercard. I thought the issue might be on the frontend, but working my way backwards came to the conclusion the issue is here on the backend.
Here is my controller:
class Api::V1::PlayercardController < ApplicationController
before_action :set_user
def index
if params[:user_id]
#playercard = #user.playercard
else
#playercard = Playercard.all
end
render json: #playercard
end
def show
#playercard = Playercard.find(params[:id])
render json: #playercard
end
def create
#playercard = Playercard.new(playercard_params)
binding.pry
if #playercard.save
render json: #user
else
render json: {
error: #playercard.errors.full_messages.to_sentence
}
end
end
def update
#playercard = Playercard.find(params[:id])
if #playercard.update(playercard_params)
render json: #playercard
else
render json: {
error: #playercard.errors.full_messages.to_sentence
}
end
end
private
def playercard_params
params.require(:playercard).permit(:player_nickname, :player_height_in_feet, :player_height_in_inches, :player_weight, :player_age, :player_fav_player, :user_id)
end
def set_user
#user = User.find(params[:user_id])
end
end
My playercard model:
class Playercard < ApplicationRecord
belongs_to :user
validates :player_nickname, :player_height_in_feet, :player_height_in_inches, :player_weight, :player_age, :player_fav_player, presence: true
end
and the serializer if that helps:
class PlayercardSerializer < ActiveModel::Serializer
attributes :id, :player_nickname, :player_height_in_feet, :player_height_in_inches, :player_weight, :player_age, :player_fav_player
belongs_to :user
end
Here are my params:
<ActionController::Parameters {"playerNickname"=>"white mamba", "playerHeightFeet"=>"6", "playerHeightInches"=>"3", "playerAge"=>"30", "playerWeight"=>"170", "playerFavPlayer"=>"Kobe", "user_id"=>"1", "controller"=>"api/v1/playercard", "action"=>"create", "playercard"=><ActionController::Parameters {"user_id"=>1} permitted: false>} permitted: false>
When I submit the form on the front end, I get errors saying each field is empty...in the pry, if I type playercard_params, only user_id shows up (with the correct id)
I solved the issue by lining up the naming convention for the attributes with the front-end and back-end. And it worked!
Thank you #jvillian for the insight!!

handling nested attributes in rails 5 api only application

I have a requirement in rails api application. client can have many orders and each order belongs to a client.
class Client < ApplicationRecord
has_many :orders
end
my order.rb is
class Order < ApplicationRecord
belongs_to :client, dependent: :destroy
accepts_nested_attributes_for :client
validates_presence_of :order_amount, :service_amount, :miners_amount
end
I have a route exposed /place_order and which creates client and orders.
class OrderProcessingController < ApplicationController
def place_order
#order = Order.new(order_processing_params)
if #order.save
render json: #order
else
render json: #order.errors.full_messages
end
end
private
def order_processing_params
params.require(:order).permit(:order_amount, :service_amount, :miners_amount, client_attributes: [:name, :email, :phone_number, :date])
end
end
Everything works fine so far. Now my requirement is, i have to check the client is already present in client table. if yes add the client_id for the orders and create new order. I don't want to create new client and order every time.
how can i achieve the same in before_filter or something like that. get the client from client params and if the client present delete the params key from incoming params ???
the post data for place_order is as follows
{
"order" : {
"order_amount" : "10000",
"service_amount" : "1000",
"miners_amount" : "10000",
"client_attributes": {
"name": "Ajith",
"email": "ajith#gmail.com",
"phone_number": "12231321312",
"date": "12/12/12"
}
}
}
Thanks in advance,
Ajith
The below code is not tested, mostly your approach should be around this
class OrderProcessingController < ApplicationController
before_action :find_client, only: [:place_order]
def place_order
#order = #client.orders.new(order_processing_params)
if #order.save
render json: #order
else
render json: #order.errors.full_messages
end
end
private
def order_processing_params
params.require(:order).permit(:order_amount, :service_amount, :miners_amount, client_attributes: [:name, :email, :phone_number, :date])
end
def find_client
#client = Client.find_or_create_by(email: params[:order][:client_attributes][:email])
#below line can be improved using a method, see the last line if later you want, never update a primary key which is email in bulk params
#client.update_attributes(name: params[:order][:client_attributes][:name], phone_number: params[:order][:client_attributes][:phone_number], date: params[:order][:client_attributes][:date])
end
#def get_client_params
# params.require(:order)
#end
end
I tried below approach to get a solution. not very sure that this is the right way to approach the problem
class OrderProcessingController < ApplicationController
before_action :find_client, only: :place_order
def place_order
if #client.present?
#order = #client.orders.build(order_processing_params)
else
#order = Order.new(order_processing_params)
end
if #order.save
render json: #order
else
render json: #order.errors.full_messages
end
end
private
def order_processing_params
params.require(:order).permit(:order_amount, :service_amount, :miners_amount, client_attributes: [:name, :email, :phone_number, :date])
end
def find_client
begin
#client = Client.find_by_email(params[:order][:client_attributes][:email])
rescue
nil
end
end
end
Thanks,
Ajith

uninitialized constant UController::User_param

I am making a basic account setup and to try to learn how the database stuff works. I have been running into this error constantly, and I have no idea how to make it disappear. I have my stuff named as U, so the URL will be easier to type a username like Reddit has it example.com/u/username
The Error is uninitialized constant UController::User_param
It highlights this code: #user = U.new(User_param)
Controller:
class UController < ApplicationController
def index
#users = U.all
end
def show
end
def create
#user = U.new(User_param)
if #user.save
redirect_to :action => 'list'
else
#user = U.all
render :action => 'new'
end
end
def User_param
params.require(:Us).permit(:id, :email, :password, :created_at, :updated_at)
end
def new
#user = U.new
end
def edit
end
end
Routes:
resources :u
U Model:
class U < ActiveRecord::Base
end
In Rails you don't capitalize methods, only constants and classes. change User_param to user_params along with the method and that should work. I made params plural since it is clearer and easier to understand
Also, change the user_param method to this:
def user_params
params.require(:u).permit(:id, :email, :password, :created_at, :updated_at)
end
The .require(:u) doesn't need to be plural as you had it.

How to create new User with an Organization association

In my webapp my User Signup page has an Organization Name field. I have an Organization model that has_many :users, and my User model belongs_to :organization. When a new user is created, I'd like for the Organization Name value to be used to create a new organization record, and associate it with the user, such that user.organization_id = the new organization id.
This is my users_controller.rb code:
class UsersController < ApplicationController
def new
#user = User.new
end
def show
#user = User.find(params[:id])
#organization = Organization.find(#user.organization_id)
end
def create
#organization = Organization.new(organization_params)
#user = User.new(user_params)
if #user.save && #organization.save
sign_in #user
redirect_to #user
flash[:success] = "Welcome to the App!"
else
flash.now[:danger] = "Uh oh, there's been an error"
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
def organization_params
params.require(:organization).permit(:name)
end
end
Right now both the user record and organization record are being created when a user submits the signup form, but the association is not saved. The user.organization_id value is nil.
Can you comment on what's wrong, and if there's a good way to do what I'm going for -- maybe with .build?
Thanks!
Brennan
Yes! .build will work, but because its a single association back, you will be using the association name in your build command, ie build_organization
def create
#user = User.new(user_params)
#user.build_organization(organization_params)
if #user.save
blah blah blah
You only need to save the user (not #organization) if done this way because the association is taken care of.
At user_params permit :organization_id ;)
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation, :organization_id)
end
EDIT: You also need to set organization_id somewhere for user - if you're not doing it in form (like with select or some else field) you can use .build method.

How to add current_user to user_id to form_for in rails?

I have a form for creating materials (title, description and content - all basic). The form saves these details just fine but it doesn't save the user_id, which should be the user_id of the current_user. How do I do this? It must be easy but nothing has worked so far.
def create
#material = Material.new(params[:material])
if #material.save
flash[:success] = "Content Successfully Created"
redirect_to #material
else
render 'new'
end
end
def create
#material = Material.new(params[:material])
#material.user_id = current_user.id if current_user
if #material.save
flash[:success] = "Content Successfully Created"
redirect_to #material
else
render 'new'
end
end
There are a few different ways to do it depending on how you have your application setup. If there is a relationship between the user and materials (User has many materials), you could use that in your controller:
def create
#material = current_user.materials.new(params[:material])
# ...
end
If you don't have that relationship, I would still recommend setting it in the controller as opposed to a hidden field in the form. This will be more secure because it won't let someone tamper with the user id value:
def create
#material = Material.new(params[:material].merge(user_id: current_user))
# ...
end
Assuming you are saving the login users's object in the current_user following will work for you
#material = Material.new(params[:material])
#material.user_id = current_user.id
if #material.save
With Rails 5 and parameters needing to be permitted before objects are created, this is the simplest way to merge the current_user into the params, kudos to #Peter Brown in his answer:
def create
#discussion = current_user.materials.new(new_material_params)
# ...
end
private
def new_material_params
params.require(:material).permit(:title, :description,: content)
end
If you have nested object creation using accepts_nested_attributes_for, you need to manually merge deep into the association parameters:
class User < ApplicationRecord
has_many :discussions # Used to associate User with Discussion later
end
class Comment < ApplicationRecord
belongs_to :user
end
class Discussion < ApplicationRecord
belongs_to :user
has_many :comments
accepts_nested_attributes_for :comments
end
class DiscussionsController < ApplicationController
def create
# Merge the params[:discussion][:user_id] by using the relationship's #new
#discussion = current_user.discussion.new(new_discussion_params)
end
private
# Sanitized params for creation, not editing
def new_discussion_params
params.require(:discussion)
.permit(:title, :user_id,
comments_attributes: [:id, :content, :discussion_id, :user_id])
.tap do |discussion_params|
# Require the association parameters, and if they exist,
# set :user_id for each.
discussion_params.require(:comments_attributes).each do |i, comment|
comment.merge!(user_id: current_user.id)
end
end
end
end
Heads up: Setting (or overwriting!) what will be params[:discussion][:comments_attributes]["0"][:user_id] works fine for creation. But if you allow editing deep hierarchies in addition to creation, make sure you don't accidentally overwrite all the :user_ids with the current user.

Resources