I have a User model generated using Devise. This User model has 2 types (Buyer or Seller) created using Polymorphic Associations.
class Buyer < ActiveRecord::Base
has_one :user, as: :owner, dependent: :destroy
accepts_nested_attributes_for :user
validates_presence_of :user
validates_associated :user
class User < ActiveRecord::Base
after_commit :transaction_success
after_rollback :transaction_failed
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :owner, polymorphic: true
validates :email, presence: true
validates :first_name, presence: true
private
def transaction_success
logger.info "Transfer succeed for Account #{self.to_param}"
end
def transaction_failed
logger.warn "Transfer failed for Account #{self.to_param}"
end
end
When an User is Registered, he does it from an specific registration link (/buyer/new or /seller/new), calling the create method from the controller:
def create
#buyer = Buyer.new(buyer_params)
#user = User.new(user_params)
respond_to do |format|
begin
User.transaction do
#buyer.save
#user.owner_id = #buyer.id
#user.owner_type = "Buyer"
#user.save
end
format.html { sign_in_and_redirect #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
rescue ActiveRecord::Rollback
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
The problem is that sometimes the transaction fails but saves a Buyer without an User. Also, the Devise validations, or any validation that I include in the User Model doesn't make any difference, allowing users to be created without any email, password etc.
How can I fix the transaction and make sure that the validations work??
Related
I'm using Mongodb in my Rails app. I have 2 models, which are Account and User. Account has many users and users belongs to account.
Account model
has_many :users, :inverse_of => :account, :dependent => :destroy
validates :organization_name, presence: true, uniqueness: true
User model
belongs_to :account, :inverse_of => :users
validates :account, :presence => false
validates :email, presence: true
has_secure_password
validates :password, length: { minimum: 6 }, allow_nil: true
def User.new_token
SecureRandom.urlsafe_base64
end
def self.create_with_password(attr={})
generated_password = attr[:email] + User.new_token
self.create!(attr.merge(password: generated_password, password_confirmation: generated_password))
end
User controller
def new
#user = User.find_by(params[:id])
#user = #current_user.account.users.new
end
def create
#user = User.find_by(params[:id])
#user = #current_user.account.users.create_with_password(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
format.js
else
format.html { render 'new' }
format.json { render json: #user.errors, status: :unprocessable_entity }
format.js { render json: #user.errors, status: :unprocessable_entity }
end
end
end
private
def user_params
params.require(:user).permit(:id, :email, :password, :password_confirmation, :owner, :admin)
end
I can successfully sign up an account with a user. But when I tried to add a new user, the user record can't be saved. I assigned a password for users when creating a new user.
The error messages:
message: Validation of User failed. summary: The following errors were found: Account can't be blank resolution: Try persisting the document with valid data or remove the validations.
If I removed the self.create_with_password and manually type in the password in the form, it works. So i guess the error must be in the self create password, it seems like doesn't save the record. By the way I'm using Rails 5.0. Any idea to solve this?
Hey #ternggio Welcome to community.
Account can't be blank.
This error appear due to belongs_to statement in user.rb.
In rails > 5 belongs_to is by default required, You can set as optional with marking optional: true.
belongs_to :account, :inverse_of => :users, optional: true
and remove below line.
validates :account, :presence => false
Hope, this will help you.
I have a Shop model and a User model. Logic is that users can have one shop and shops can have one users associated with them, so I am using the has_one: shop association.
But while creating a new shop for a new user am getting this error
undefined method 'shops' for #<\User:0x007f6f30659068> Did you mean? shop shop=
I don't understand what's gone wrong. I am sure I must have done something stupid, here's my code:
class ShopsController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
def new
#shop = current_user.shop.build
end
def create
#shop = current_user.shops.build(shop_params)
#shop.user = current_user
respond_to do |format|
if #shop.save
format.html { redirect_to #shop, notice: 'Shop was successfully created.' }
format.json { render :show, status: :created, location: #shop }
else
format.html { render :new }
format.json { render json: #shop.errors, status: :unprocessable_entity }
end
end
end
private
def shop_params
params.require(:shop).permit(:name, :description, :imageshop, :location, :web, :email, :phone, :business_type, :category)
end
end
class Shop < ApplicationRecord
mount_uploader :imageshop, ImageUploader
belongs_to :user
end
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :products, dependent: :destroy
has_one :shop
end
I think you need to change
#shop = current_user.shops.build(post_params)
to
#shop = current_user.build_shop(post_params)
This is because you have specified that a User can have one Shop.
Hope it helps!
Here how I would like things to work. I am not sure it is possible this way…
The Seller registers and can create a Resa which attribute is request_email: [DONE]
Once the Resa is created, an e-mail is sent to the request_email [DONE] asking to click on the link to register as a Buyer.
In this Buyer registration form, the e-mail field should be pre-filled with the request_email from the Resa. Once the buyer is saved, the Resa object should see its attribute buyer_id be updated from nilto the id of the Buyer object created.
Devise was added to Seller and Buyer.
Questions: are the following models and associations correctly designed to allow the process described above?
If yes, how to pass the resa_id and the request_email in the link for creating the Buyer (pre-filled form) ?
Please feel free to suggest a smarter way to do things if you feel this is the wrong way.
models/seller.rb
class Seller < ActiveRecord::Base
has_many :resas
has_many :buyers, :through => :resas
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
end
models/resa.rb
class Resa < ActiveRecord::Base
belongs_to :seller
belongs_to :buyer
end
models/buyer.rb
class Buyer < ActiveRecord::Base
has_many :resas
has_many :sellers, :through => :resas
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
end
controllers/resas_controller.rb
class ResasController < ApplicationController
before_action :set_resa, only: [:show, :edit, :update, :destroy]
before_action :authenticate_seller!
…
def create
#resa = current_seller.resas.new(resa_params)
#resa.request_status = "Pending"
##resa.seller_id = current_seller.id
respond_to do |format|
if #resa.save
ResaMailer.request_mail(#resa).deliver
format.html { redirect_to #resa, notice: 'Resa was successfully created.' }
format.json { render action: 'show', status: :created, location: #resa }
else
format.html { render action: 'new' }
format.json { render json: #resa.errors, status: :unprocessable_entity }
end
end
end
…
end
controllers/buyers_controller.rb
class BuyersController < ApplicationController
def create
#buyer = Buyer.new(buyer_params)
#resa = Resa.find(params[:resa_id])
respond_to do |format|
if #buyer.save
format.html { redirect_to #buyer, notice: 'Buyer was successfully created.' }
format.json { render action: 'show', status: :created, location: #buyer }
else
format.html { render action: 'new' }
format.json { render json: #buyer.errors, status: :unprocessable_entity }
end
end
end
end
Please let me know if you need further informations.
I assume your ResaMailer.request_mail is generating the link for the buyer registration. So in this link you can add a token
http://your.site/buyer/new?token=abcdef
The idea is to generate a token, store it in a table (perhaps your resas table) and along in the same record you can store the other fields you will need to retrieve during the buyer registration (like request_email for example)
Then in your BuyersController new action you can fetch the data using that token, and pre-fill the form.
class BuyersController
def new
#resa = Resa.find_by(token: params[:token])
# Use #resa to prefil the form in `new` action
end
end
As for the buyer_id you can't get a valid id before the record is created, but if your concern is to link the resa record with the newly created buyer, you can use the token I mentioned earlier to retrieve the resa record's id at the time of the buyer registration, then update this record with the newly created buyer id.
Hope it's clear, let me know.
I have two models: User and Sensor. I want to set dependence has_many and belongs_to.
Sensor model
class Sensor < ActiveRecord::Base
attr_accessible :user_id, :data, :ids, :voltage, :status
belongs_to :user
end
and User model
class User < ActiveRecord::Base
has_many :sensors
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
In the new migration i created new column
class AddUserId < ActiveRecord::Migration
def change
add_column :sensors, :user_id, :integer
end
end
And Create method in the Sensor Controller
def create
#sensor = Sensor.new(sensor_params)
respond_to do |format|
if #sensor.save
format.html { redirect_to #sensor, notice: 'Sensor was successfully created.' }
format.json { render action: 'show', status: :created, location: #sensor }
else
format.html { render action: 'new' }
format.json { render json: #sensor.errors, status: :unprocessable_entity }
end
end
end
And when i press the create button,the dependence doesn't set
I guess you have current_user in your application.
SO in the create action, please try the following code.
def create
#sensor = current_user.sensors.new(sensor_params)
# YOUR CODE GOES HERE
end
I have two models User and Promotion, an user can create has_many promotion and an promotion belong to user so :
promotion.rb
class Promotion < ActiveRecord::Base
belongs_to :user
belongs_to :good
validates :name, :presence => true
validates :title, :presence => true
validates :description, :presence => true
end
for the users i used devise so:
user.rb
class User < ActiveRecord::Base
has_many :promotions ,:foreign_key => "user_id",
:dependent => :destroy
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook]
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me,:provider,:uid,:address,:name,:surname,:supplier,:partita_iva,:state,
:gender ,:language,:bio,:work,:education
now when i want create a new promotions get this error
NoMethodError in PromotionsController#create
undefined method `promotions' for nil:NilClass
this is the controller:
def create
#user = User.find_by_id(params[:user_id])
#promotion =#user.promotions.create(:params[:promotion])
redirect_to promotion_patch(#promotion)
respond_to do |format|
if #promotion.save
format.html { redirect_to #promotion, notice: 'Promotion was successfully created.' }
format.json { render json: #promotion, status: :created, location: #promotion }
else
format.html { render action: "new" }
format.json { render json: #promotion.errors, status: :unprocessable_entity }
end
end
end
help please :)
It looks as though params[:user_id] did not contain a valid user id. Since you used find_by_id instead of find, it quietly assigned nil to #user, and of course nil doesn't have a method named #promotions, so that line failed.
You need to either check for #user being nil, or change User.find_by_id to User.find and then rescue ActiveRecord::RecordNotFound. In either case, respond with a custom 404 or whatever other way seems appropriate.
One other question, is it your intention that a user can create promotions for any other user? If they should only be creating promotions for themselves, you can avoid this whole mess by just eliminating the whole User.find_by_id line, and changing the next line to:
#promotion = current_user.promotions.create(params[:promotion])
Devise should have already current_user for you. In any case, you also need to handle what happens if the promotion cannot be created because there are validation errors in the user-supplied parameters.