Can't mass-assign protected attributes: - ruby-on-rails

Have tried the solutions for this common error in stackoverflow but none of them seem to work in this case, it might be that I already created an address field on the property before. I keep getting the mass assignment error.
Any help appreciated.
Address.rb
class Address < ActiveRecord::Base
attr_accessible :addressable_id, :addressable_type, :city, :county, :postcode, :street1, :street2
belongs_to :addressable, :polymorphic => true
end
Property.rb
class Property < ActiveRecord::Base
attr_accessible :name, :addresses_attributes
belongs_to :user
has_one :address, :as => :addressable
accepts_nested_attributes_for :address
validates :name, presence: true, length: { maximum: 200 }
validates :address, presence: true
validates :user_id, presence: true
end
Property Controller
class PropertiesController < ApplicationController
before_filter :authenticate_user!
before_filter :correct_user, only: :destroy
def index
#property= Property.all
end
def create
#property = current_user.properties.build(params[:property])
if #property.save
flash[:success] = " Property Added"
redirect_to root_path
else
render 'edit'
end
end
def new
#property = Property.new
#property.build_address
end

You should add
accepts_nested_attributes_for :address
and change
attr_accessible :name, :address_attributes
and if it doesn't work change both address to addressable

Related

Belongs_to relationship in edit

I'm encountering a problem when editing a form with a belongs_to relationship (extra_guest belongs_to age_table).
I am able to create a new extra_guest and assign it to an age_table, but I cannot get the edit/update to work as my update function returns a falseClass.--> #extra_guest.update(extra_guest_params).errors.full_messages returns undefined method `errors' for false:FalseClass
Code
models
class ExtraGuest < ApplicationRecord
belongs_to :age_table
validates :age_table, presence: true
end
class AgeTable < ApplicationRecord
belongs_to :park
has_many :extra_guests, dependent: :destroy
validates :name, :age_from, :age_to, presence: true
validates_associated :extra_guests
end
class Attraction < ApplicationRecord
belongs_to :park
has_many :extra_guests, dependent: :destroy
accepts_nested_attributes_for :extra_guests, allow_destroy: true
validates :name, presence: true
end
class Park < ApplicationRecord
has_many :attractions, dependent: :destroy
has_many :age_tables, dependent: :destroy
validates :name, :currency, presence: true
end
extra_guests_controller
def edit
#extra_guest = ExtraGuest.find(params[:id])
#age_table = #extra_guest.age_table
#age_table_list = AgeTable.where(park: #attraction.park)
end
def update
#extra_guest = #attraction.extra_guests.find(params[:id])
#age_table = AgeTable.find(params[:age_table])
authorize #extra_guest
if #extra_guest = #extra_guest.update(extra_guest_params)
redirect_to root_path
else
#attraction = Attraction.find(params[:attraction_id])
#extra_guest = ExtraGuest.find(params[:id])
#age_table_list = #attraction.park.age_tables
render 'edit'
end
end
private
def extra_guest_params
params.require(:extra_guest).permit(:name, :age_table_id,
extra_guest_prices_attributes: [:id, :name, :price_type, :start_date, :end_date, :price, :duration, :duration_min, :duration_max, :backend_only, :weekend_extra, :_destroy])
end
views/extra_guests/form
<%= simple_form_for [#attraction, #extra_guest] do |f|%>
<%= f.input :age_table, :as => :select, :selected => #age_table.id, :collection => #age_table_list.map {|u| [u.name, u.id]}, :include_blank => false %>
<% f.button :submit %>
Error message + params
Couldn't find AgeTable without an ID
{"utf8"=>"✓",
"_method"=>"patch",
"authenticity_token"=>"l8HMnVIRybZg==",
"extra_guest"=>
{"age_table"=>"104",
"extra_guest_prices_attributes"=>
{"0"=>{"price"=>"1.0", "weekend_extra"=>"", "start_date"=>"2019-10-15", "end_date"=>"20-09-2019", "duration"=>"", "duration_min"=>"", "duration_max"=>"", "_destroy"=>"false", "id"=>"42"},
"1"=>{"price"=>"1.0", "weekend_extra"=>"", "start_date"=>"2019-10-15", "end_date"=>"2019-10-16", "duration"=>"", "duration_min"=>"", "duration_max"=>"", "_destroy"=>"false", "id"=>"43"}}},
"commit"=>"Save new option",
"attraction_id"=>"185",
"id"=>"55"}
Method update returns true or false. You can find docs here. To check errors you need to call method errors on #extra_guest object.
#extra_guest.update(extra_guest_params)
#extra_guest.errors.full_messages

How to combine information from two tables when creating a JSON on Ruby on Rails?

What is the best approach to combine information from two different tables on Ruby on Rails, when building a JSON for Web Services purpose?
I want to combine my list of clients with a tag that is taken from another table than users table.
Here is how I proceed from the controller
def clients
#orders = #bar.orders
#users = User.where(id: #orders.pluck(:user_id).uniq).all
#tags = UserTag.where(bar: #bar, user_id: #orders.pluck(:user_id).uniq).all
end
The view is built this way
json.user_tags do
json.array!(#tags) do |user_tag|
json.extract! user_tag, :id, :bar_id, :user_id, :tag
end
end
json.users do
json.array!(#users) do |user|
json.extract! user, :id, :first_name, :last_name, :email, :facebook_id, :context, :created_at, :updated_at, :company, :phone, :birthdate, :stripe_customer_id, :bar_id, :role
end
end
The JSON generated with this code looks like this
I would like to integrate the tag field directly in users array, next to other users information such as on this illustration
The UserTag model is built like that
class UserTag < ActiveRecord::Base
belongs_to :user, :counter_cache => true
belongs_to :bar
validates_uniqueness_of :bar_id, :user_id, :scope => :bar_id
acts_as_paranoid without_default_scope: true
def self.default_scope
with_deleted
end
def api_error_message
errors.full_messages.join("\n")
end
end
And User model:
class User < ActiveRecord::Base
has_many :access_tokens, dependent: :destroy
belongs_to :club
belongs_to :bar
enum role: [:user, :club_owner, :waiter, :admin]
has_many :club_comments
has_many :club_subscriptions
has_many :artist_subscriptions
has_many :artist_votes
has_many :payments
has_many :carts
has_many :user_entrances
has_many :bookings, through: :user_entrances
has_many :booking_events, through: :user_entrances
has_many :cart_item_consumptions
has_many :clientlist_elements
has_secure_password
has_one :address, as: :addressable
accepts_nested_attributes_for :address
validates :password, length: {minimum: 8}, if: :validate_password?
validates :password_confirmation, presence: true, if: :validate_password?
validates :email, presence: true, if: :user_context_email
validates :email, email: true, if: :user_context_email
validates :email, :facebook_id, uniqueness: true, :allow_blank => true, :allow_nil => true
validates :first_name, presence: true
validates :last_name, presence: true
reverse_geocoded_by :latitude, :longitude
after_create :create_access_token
after_save :update_vote_position_if_needed
def validate_password?
password.present? || password_confirmation.present?
end
def name
"#{first_name.capitalize} #{last_name.capitalize}"
end
def create_access_token
AccessToken.create(user: self)
end
def user_context_email
context == 0
end
def user_context_fb
context == 1
end
def update_vote_position_if_needed
if self.latitude_changed? || self.longitude_changed?
self.delay.update_vote_position
end
end
def update_vote_position
self.artist_votes.each do |vote|
vote.latitude = self.latitude
vote.longitude = self.longitude
vote.save
end
end
def stripe_description
"#{first_name} #{last_name} - #{email}"
end
def stripe_customer_metadata
{"User_id" => self.id, "Firstname" => self.first_name, "Lastname" => self.last_name, "Email" => self.email, "Phone" => self.phone}
end
def api_error_message
errors.full_messages.join("\n")
end
end
EDIT
I tried the #krishnar solution, here is how the JSON looks like now
The users are duplicated and only users with tag appear (we need to display all users even those without tags)
Modify user model to have association:
class User < ActiveRecord::Base
# define user to user_tags association
has_many :user_tags
end
Join users table with user_tags and select user_tags id as tag to use in json file:
def clients
#orders = #bar.orders
#users = User.where(id: #orders.pluck(:user_id).uniq).joins("left join user_tags on users.id=user_tags.user_id and user_tags.bar_id='#{#bar.id}'").select("users.*","user_tags.id as tag")
#tags = UserTag.where(bar: #bar, user_id: #orders.pluck(:user_id).uniq).all
end
Now you can access tag in #users array:
json.users do
json.array!(#users) do |user|
json.extract! user, :id, :first_name, :last_name, :email, :facebook_id, :context, :created_at, :updated_at, :company, :phone, :birthdate, :stripe_customer_id, :bar_id, :role, :tag
end
end

Rails - Nested Strong parameters

I'm trying to create an user register using two models User and profile, nested strong parameters in one controller. when I send parameter I get this error unknown attribute 'profiles_attributes' for User. and I can't create user neither profile :
class User < ActiveRecord::Base
has_one :profile
has_many :apartments
has_many :session
has_secure_password
validates :email, presence: true, uniqueness: true
validates :password, presence: true
accepts_nested_attributes_for :profile
end
class Profile < ActiveRecord::Base
belongs_to :user
belongs_to :city
has_many :profile_universities
has_many :universities, through: :profile_universities
has_many :profile_preferences
has_many :preferences, through: :profile_preferences
has_one :photo, :as => :imageable
end
class Api::V1::UserController < ApplicationController
before_action :user_params
def create_without_facebook
#user= User.new(user_params)
if #user.save
#profile = Profile.new(user_params[:profiles_attributes])
render json: [#user, #profile]
else
render json: #user.errors, status: :unprocessable_entity
end
end
def user_params
params.require(:user).permit(:email, :password, profiles_attributes: [:first_name, :last_name, :birthday, :gender, :marital_status, :ocupation, :budget, :question, :about, :city])
end
end
use the singular profile_attributes if it's a has_one

Rails 4 validation error with has_many through association

I have troubles creating the records in an association with rails 4. It's basically an association between Entry and Author, with a join table in the middle called AuthorsEntry. The schema is the following:
class Entry < ActiveRecord::Base
validates :name, presence: true
validates :from, presence: true
validates :to, presence: true
belongs_to :event
has_many :authors, through: :authors_entry
has_many :authors_entry
class AuthorsEntry < ActiveRecord::Base
validates :author, presence: true
validates :entry, presence: true
belongs_to :author
belongs_to :entry
end
class Author < ActiveRecord::Base
belongs_to :event
has_many :entries, through: :authors_entry
has_many :authors_entry
validates :name, presence: true
validates :event, presence: true
end
In my program_entries_controller.rb I have the following methods:
def create
#program_entry = Entry.new(program_entry_params)
author_ids_params.each do |id|
#program_entry.authors << AuthorsEntry.build(author_id: id)
end
#program_entry.event = #event
if #program_entry.save
flash[:notice] = t(:program_entry_created_successfully)
redirect_to organizer_event_program_entry_path(#event, #program_entry)
else
render :new
end
end
def program_entry_params
params.require(:program_entry).permit(
:name, :abstract, :'from(1i)', :'from(2i)', :'from(3i)',
:'from(4i)', :'from(5i)', :'to(1i)', :'to(2i)', :'to(3i)', :'to(4i)',
:'to(5i)'
)
end
def author_ids_params
params.require(:program_entry).permit(:author_ids => [])
end
I already have the authors saved in my database, the create action should just add a new record for the Entry model and the association (authors_entry) table. But when I try saving the entry it always returns "is_invalid" over authors_entry.
The join table should be named AuthorEntries to follow rails convention.

Nested attributes with polymorphic association in Rails 5

I've created an Address model with a polymorphic association, I am trying to save to it though nested attributes of a client model but I am getting Address addressable must exist in the #client.errors.
Models:
class Client < ApplicationRecord
has_one :address, as: :addressable, dependent: :destroy
accepts_nested_attributes_for :address, :allow_destroy => true
end
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
Controller:
class ClientsController < ApplicationController
def new
#client = Client.new
#client.create_address
end
def create
#client = Client.new(client_params)
if #client.save
...
else
...
end
end
private
def client_params
params.require(:client).permit(:first_name ,:last_name, :company, address_attributes: [:line1, :line2, :line3, :city, :state_province, :postal_code, :country])
end
end
You should add the inverse_of key on your belongs_to relation, e.g. on your Address class:
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true, inverse_of: :addressable
end
This will save the nested address correctly as Rails will now correctly know what to assign in the addressable.
Don't use the optional key unless the addressable is truly optional.
belongs_to :xx, polymorphic: true, optional: true
Also
optional: true
tricking the problem, you may keep relationships mandatory by breaking creation in controller in two steps.
def client_params
params.require(:client).permit(:first_name ,:last_name, :company)
end
def address_params
params.require(:client).require( :address_attributes).permit(:line1, :line2, :line3, :city, :state_province, :postal_code, :country )
end
def create
#client = Client.new(client_params)
if #client.save
#client.create_address( address_params )
...
this may look uglier but it keeps relations safer.

Resources