Can't mass-assign protected attributes: even if attr_accessible already added - attr-accessible

Can't mass assign :title, :url and :about even if attr_accessible attributes already added. It's fine on rails console but not on online form.
Post Model:
class Post < ActiveRecord::Base
attr_accessible :about, :downv, :names, :points, :title, :upv, :url, :user_id
belongs_to :user
end
User Model:
class User < ActiveRecord::Base
attr_accessible :email, :password_digest, :post_id, :password, :password_confirmation, :name
has_many :posts
has_secure_password
validates_presence_of :password, :on => :create
end
Post Controller create:
def create
#post = User.new(params[:post])
#post.upv, #post.downv, #post.points = 0, 0, 0
#post.user_id = params[:user_id]
#post.names = ""
if #post.save
redirect_to root_url, notice: "Post created."
else
render "new"
end
end
My form view is is just like any other form view.

instead of Post.new I typed User.new, SOLVED!!!

Related

Rails Client side Collection Validation fails - Simple Form

I have to build a simple app that allows users to loan and borrow books. Simply put a User can create books, and they can pick another user to loan the book to.
I have three models User, Book and Loan:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :books
has_many :loans, through: :books
has_many :borrowings, class_name: "Loan"
validates :username, uniqueness: true
validates :username, presence: true
end
class Book < ActiveRecord::Base
belongs_to :user
has_many :loans
validates :title, :author, presence: true
end
class Loan < ActiveRecord::Base
belongs_to :user
belongs_to :book
validates :user, :book, :status, presence: true
end
The LoansController looks like this:
class LoansController < ApplicationController
before_action :find_book, only: [:new, :create]
def new
#users = User.all
#loan = Loan.new
authorize #loan
end
def create
#loan = Loan.new
#loan.book = #book
#loan.user = User.find(loan_params[:user_id])
#loan.status = "loaned"
authorize #loan
if #loan.save
redirect_to :root
else
render :new
end
end
private
def loan_params
params.require(:loan).permit(:user_id)
end
def find_book
#book = Book.find(params[:book_id])
end
end
My form looks like:
<%= simple_form_for([#book, #loan]) do |f| %>
<%= f.input :user_id, collection: #users.map { |user| [user.username, user.id] }, prompt: "Select a User" %>
<%= f.submit %>
<% end %>
If I submit the form without selecting a user, and keep the "Select a User" prompt option, the form is submitted and the app crash because it can't find a user with id=
I don't know why the user presence validation in the form does not work...
you will change your Create method
def create
#loan = Loan.new
#loan.book = #book
#loan.user = User.find_by_id(loan_params[:user_id])
#loan.status = "loaned"
authorize #loan
if #loan.save
redirect_to :root
else
render :new
end
end

Rails nested attributes type mispatch error

I am creating a rails api using rails_api gem, I have a model name User and another model named Identity.
The issue I am facing is that whenever I tries to create user from params with nested_attributes it gives me ActiveRecord::AssociationTypeMismatch error
Models
User.rb
class User < ActiveRecord::Base
enum gender: [:male , :female]
has_many :identities ,dependent: :destroy
accepts_nested_attributes_for :identities
has_secure_password
end
Identity.rb
class Identity < ActiveRecord::Base
belongs_to :user
validates_associated :user
end
Controllers
users_controller.rb
class UsersController < ApplicationController
def create
#user = User.new user_params
##user.build.identities(user_params[:identities])
if #user.save
render json: #user , status: :created
else
render json: #user.errors, status: :unprocessable_entity
end
end
private
def user_params
json_params = ActionController::Parameters.new( JSON.parse(request.body.read) )
json_params.require(:user).permit(:first_name, :last_name, :email, :password, :image, :location, :gender,{identities: [:provider, :uid, :url, :token, :expires_at]})
end
end
I am sending the data as json object:
This is the error in server console:
Kindly help me fix this issue. I have tried all the possible solutions. Thanks in advance
Your strong param should be like this:
json_params.require(:user).permit(:first_name, :last_name, :email, :password, :image, :location, :gender,identities_attributes: [:provider, :uid, :url, :token, :expires_at])
json_params.require(:user).permit(:first_name, :last_name, :email, :password, :image, :location, :gender, :identities => [:provider, :uid, :url, :token, :expires_at])
this will resolve your issue as in current way.

How to create nested models from API request?

I've a Rails API and I've two models:
class Event < ActiveRecord::Base
belongs_to :category
has_many :event_categories
has_many :events, through: :event_categories
attr_accessible :title, :description, :event_categories_attributes
accepts_nested_attributes_for :event_categories
end
and
class EventCategory < ActiveRecord::Base
belongs_to :event
belongs_to :category
attr_accessible :category_id, :event_id, :principal
validates :event, :presence => true
validates :category, :presence => true
validates_uniqueness_of :event_id, :scope => :category_id
end
In a first moment, EventCategory didn't exist so I created Event resources sending params like event[title]='event1', event[description] = 'blablbla' thought POST REST request.
My API EventsController was like this (I haven't a new method because I don't need views):
def create
#event = Event.create(params[:event])
if #event
respond_with #event
else
respond_with nil, location: nil, status: 404
end
end
This way worked correctly for me. Now, with the new EventCategory model I don't know how I could create EventCategories models at the same time.
I've trying this... but it doesn't work:
def create
#event = Event.new(params[:event])
#event.event_categories.build
if #event.save
respond_with #event
else
respond_with nil, location: nil, status: 404
end
end
Rails told me:
{
"event_categories.event": [
"can't be blank"
],
"event_categories.category": [
"can't be blank"
]
}
I send the category_id like this:
event[event_categories_attributes][0][category_id] = 2
Any ideas?
In your create action, instead of this:
#event.event_categories.build
Try this:
#event.event_categories = EventCategory.new do |ec|
ec.event = #event
ec.category = the_cattegory_you_want_to_specify
# You need both of these as you are validating the presence of event AND category
end

Rails how to get associated model attributes

I have the method below which saves data to the users table as well as the user_details table.
When i pass the #newUser variable to the EmailMailer, i can't access the user_details attributes. How can i pass the user_details in the #newUser object without having to re-query the database?
Models
class User < ActiveRecord::Base
has_one :user_details, :dependent => :destroy
accepts_nested_attributes_for :user_details
attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :login, :home_phone, :cell_phone, :work_phone, :birthday, :home_address, :work_address, :position, :company, :user_details_attributes
end
class UserDetails < ActiveRecord::Base
belongs_to :user
attr_accessible :first_name, :last_name, :home_phone, :cell_phone, :work_phone, :birthday, :home_address, :work_address, :position, :company
end
Controller
# POST /users
def create
#newUser = User.new(params[:user], :include =>:user_details)
# create password
require 'securerandom'
password = SecureRandom.urlsafe_base64(8)
#newUser.password = password
respond_to do |format|
if #newUser.save
#newUser.build_user_details
# Tell the UserMailer to send a welcome Email after save
EmailMailer.welcome_email(#newUser).deliver
# To be used in dev only. Just tests if the email was queued for sending.
#assert ActionMailer::Base.deliveries.empty?
format.html {
flash[:success] = "User created successfully"
redirect_to(contacts_path)
}
else
format.html {
flash[:error] = flash[:error].to_a.concat resource.errors.full_messages
redirect_to(contacts_path)
}
end
end
end
Something like this might do what you are after.
class User < ActiveRecord::Base
has_one :user_details
accepts_nested_attributes_for :user_details
after_initialize :build_user_details
...
end
# In controller
def create
#new_user = User.new
#new_user.attributes = params[:user]
if #new_user.save
# do mail thing
else
# other thing
end
end
You need to build the UserDetails association prior to saving #newUser
#newUser.build_user_details
if #newUser.save
#send mailer
else
#do something else
end
Alternatively you could use the create action after the #newuser is saved
if #newUser.save
#newUser.create_user_details
#send mailer
else
#do something else
end
By the way, Ruby/Rails convention is to use snake_case for variables. so #newUser should be #new_user.

Nested objects in form not validating

I have a nested form where users can book appointments. However, I've noticed an issue with the form where a user can fill out the required Client model fields and not the required Appointment model fields and the form still submits since for some reason the validation on the Appointment model isn't being triggered. The only time the Appointment validation is triggered is when the associated form fields are populated. How do I get the nested form to verify that the Appointment fields are being filled out? Since clients can have multi
Customer model:
class Customer < ActiveRecord::Base
has_many :appointments
accepts_nested_attributes_for :appointments
attr_accessible :name, :email, :appointments_attributes
validates_presence_of :name, :email
validates :email, :format => {:with => /^[^#][\w.-]+#[\w.-]+[.][a-z]{2,4}$/i}
validates :email, :uniqueness => true
end
Appointment model:
class Appointment < ActiveRecord::Base
belongs_to :customer
attr_accessible :date
validates_presence_of :date
end
Customers controller:
class CustomersController < ApplicationController
def new
#customer = Customer.new
#appointment = #customer.appointments.build
end
def create
#customer = Customer.find_or_initialize_by_email(params[:customer])
if #customer.save
redirect_to success_customers_path
else
# Throw error
#appointment = #customer.appointments.select{ |appointment| appointment.new_record? }.first
render :new
end
end
def success
end
end
Customers form view:
= simple_form_for #customer, :url => customers_path, :method => :post, :html => { :class => "form-horizontal" } do |customer_form|
= customer_form.input :name
= customer_form.input :email
= customer_form.simple_fields_for :appointments, #appointment do |appointment_form|
= appointment_form.input :date
UPDATE: Providing routes
resources :customers, :only => [:new, :create] do
get :success, :on => :collection
end
If a customer has to have an appointment:
class Customer < ActiveRecord::Base
has_many :appointments
accepts_nested_attributes_for :appointments
attr_accessible :name, :email, :appointments_attributes
validates_presence_of :name, :email, :appointment # <- add your appointment
....
end
This will require each customer has at least one appointment.
EDIT based on comment
Instead of using build in your controller, I think you can use create instead which will then associate that appointment with the customer and force validation.
Customers controller:
def edit
#customer = Customer.find_or_initialize_by_email(params[:customer])
#appointment = #customer.appointments.create
end
And you'd do the same in your new method

Resources