Cannot get accepts_nested_attributes to work in rails 3 - ruby-on-rails

This might be a case of me being blind…
Somehow I cannot get my layout_positions_attributes to arrive at layout_positions
l = Layout.new
…
[17] pry(main)> l.layout_positions
=> []
[18] pry(main)> l.layout_positions_attributes=[{:name=>'xxx'}]
=> [{:name=>"xxx"}]
[19] pry(main)> l.layout_positions
=> [] # WTF!
[20] pry(main)> l.layout_positions.build({:name=>'xxx'})
=> #<LayoutPosition id: nil, name: "xxx", active: true, columns: nil, rows: nil, layout_id: nil, pos: -1>
[21] pry(main)> l.layout_positions
=> [#<LayoutPosition id: nil, name: "xxx", active: true, columns: nil, rows: nil, layout_id: nil, pos: −1>]
The parent class:
class Layout < ActiveRecord::Base
attr_accessible :name, :active, :layout_positions_attributes
has_many :layout_positions
accepts_nested_attributes_for :layout_positions,
:reject_if => lambda { |a| a[:content].blank? },
:allow_destroy => true
validates_presence_of :name
end
And where the attributes should go…
class LayoutPosition < ActiveRecord::Base
attr_accessible :name, :active, :columns, :rows, :pos
belongs_to :layout
validates_presence_of :name
end

You're telling it to reject it if the content for the layout_position object is blank. In your example, above "WTF", you're not passing through any content. Therefore this is deleting the attributes.
Calling build doesn't rely on accepts_nested_attributes_for and so will work just fine.

Related

Create child association from controller

I have 2 associated models and am trying to create the child from the parent's controller:
class Purchase < ActiveRecord::Base
has_many :comments, as: :commentable, dependent: :destroy
accepts_nested_attributes_for :comments, reject_if: :all_blank, allow_destroy: true
end
class Comment < ActiveRecord::Base
belongs_to :employee
belongs_to :commentable, polymorphic: true
validates_presence_of :body, :employee_id, :commentable_id, :commentable_type
end
In my controller I accept the params for comment:
def create
#purchase = Purchase.new(purchase_params)
if #purchase[:discount] && #purchase[:discount] > 0
#purchase[:discount] = #purchase[:discount].round(3)
end
if #purchase.save
render json: #purchase, status: :created
else
p "errors", #purchase.errors
render json: #purchase.errors.full_messages, status: :unprocessable_entity
end
end
private
def purchase_params
params.require(:purchase).permit(
:sale_type, :weeks, :weekly_cost, :date, :discount, :client_id, :id, :created_at, :updated_at, :employee_id, :consultation_id, :program_id, :purchaseable_type, :purchaseable_id,
comments_attributes: [:body, :id, :employee_id, :commentable_type]
)
end
When I attempt to create the purchase with the following params, I get the error:
purchase = {
client_id: client.id,
weeks: 5,
weekly_cost: 295,
comments_attributes: [{
employee_id: employee.id,
body: "This is a test",
commentable_type: "Purchase"
}]
}
#<ActiveModel::Errors:0x00007fb0ef3849e0 #base=#<Purchase id: nil, weeks: 5, weekly_cost: 295.0, created_at: nil, updated_at: nil, client_id: 18, discount: nil, employee_id: nil, comment: nil, referral_used: false, deleted_at: nil, date: nil, sale_type: nil, purchaseable_type: nil, purchaseable_id: nil, program_id: nil>, #messages={:"comments.commentable_id"=>["can't be blank"]}, #details={:"comments.commentable_id"=>[{:error=>:blank}]}>
There's no way to know the commentable_id before saving the purchase. What am I missing?

ActiveRecord ignores validate

Heya im pulling my hair out right now
class Referal < ApplicationRecord
validates :pax, :presence => true
validates :customer_email, presence: true
default_scope -> { order('created_at DESC') }
self.implicit_order_column = "created_at"
belongs_to :referer, class_name: "User"
belongs_to :customer, class_name: "User"
belongs_to :business
<Referal:0x000055f8a468b058
id: nil,
state: nil,
handle: nil,
sec_code: nil,
pax: nil,
booking_date_time: nil,
business_id: "224cd62b-3d29-41ca-a1be-f308815514b2",
customer_id: nil,
referer_id: "cdfb1861-d5e4-4650-9783-4189cffde6bd",
customer_email: nil,
customer_mobile: nil,
customer_last_name: nil,
customer_first_name: nil,
created_at: nil,
updated_at: nil>
x.valid?
=> true
i tried multiple ways but it seems since i have multiple FK's in the model it only validates the ft for Business and Referer
how do i enforce the validator for additional fields? thanks

Rails rolify gem /assosiation issue

I use rolify gem with devise for AdminUser
my Roles table
class RolifyCreateRoles < ActiveRecord::Migration
def change
create_table(:roles) do |t|
t.string :name
t.references :resource, :polymorphic => true
t.timestamps
end
create_table(:admin_users_roles, :id => false) do |t|
t.references :admin_user
t.references :role
end
add_index(:roles, :name)
add_index(:roles, [ :name, :resource_type, :resource_id ])
add_index(:admin_users_roles, [ :admin_user_id, :role_id ])
end
end
model 'Role'
class Role < ActiveRecord::Base
has_and_belongs_to_many :admin_users, :join_table => :admin_users_roles
belongs_to :resource,
:polymorphic => true
validates :resource_type,
:inclusion => { :in => Rolify.resource_types },
:allow_nil => true
scopify
end
my issue is when i want to get users witch belong to role it gives empty array instead of my adminuser object
u = AdminUser.first
u.add_role(:admin)
u.roles => #<Role id: 1, name: "admin", admin_user_id: 1, resource_id: nil, resource_type: nil, created_at: "2016-06-16 15:03:33", updated_at: "2016-06-17 09:04:30">
and when i do
Role.first=> #<Role id: 1, name: "admin", admin_user_id: 1, resource_id: nil, resource_type: nil, created_at: "2016-06-16 15:03:33", updated_at: "2016-06-17 09:29:32">
Role.first.admin_users => []
To check if a user has a global role:
user = User.find(1)
user.add_role :admin # sets a global role
user.has_role? :admin
=> true
Or to check at instance level In your case
u = AdminUser.first
u.add_role(:admin)
> Role.first=> #<Role id: 1, name: "admin", admin_user_id: 1,
> resource_id: nil, resource_type: nil, created_at: "2016-06-16
> 15:03:33", updated_at: "2016-06-17 09:29:32">
Instead of doing this => Role.first.admin_users => []
Try
u = AdminUser.first
u.roles
Rolify has a pretty clear documentation
Rolify
oh i fixed it by changing relation in my admin_user model
from has_many to has_and_belongs_to_many :roles

How to make sure child object is valid while saving parent?

let say that I have two class
class User
attr_accessible :name
has_one :address
validates :name, :presence => true
validates_associated :address
end
class Address
attr_accessible :country, :user_id
belongs_to :user
validates :country, :presence => true
validates :user, :presence => true
end
Now when i try to create invalid Address then it fails(which is good)
a = Address.new
a.valid? #=> false
But when i build User with invalid Address then it pass(which is bad)
u = User.first
u.build_address
u.valid? #=> true
u.save #=> true
Due to this User has Address with country => nil.
How can i tell Rails to not save Address if its invalid?
FIXED: I fixed this by adding follow line to the code. Thank you everyone.
validates_associated :address, :if => :address
class User
attr_accessible :name
has_one :address, :validate => true
validates :name, :presence => true
validates_associated :address
end
You need to also validate that an Address is actually present for User:
class User < ActiveRecord::Base
validates :address, :associated => true, :presence => true
end
With that in place, I get:
>> u = User.first
=> #<User id: 1, name: "Bob", created_at: "2013-10-09 15:17:21", updated_at: "2013-10-09 15:17:21">
>> u.build_address
=> #<Address id: nil, user_id: 1, country: nil, created_at: nil, updated_at: nil>
>> u.valid?
=> false
>> u.errors
=> #<ActiveModel::Errors:0x007fe1d6919b18 #base=#<User id: 1, name: "Bob", created_at: "2013-10-09 15:17:21", updated_at: "2013-10-09 15:17:21">, #messages={:address=>["is invalid"]}>
>> u.address.errors
=> #<ActiveModel::Errors:0x007fe1d69197a8 #base=#<Address id: nil, user_id: 1, country: nil, created_at: nil, updated_at: nil>, #messages={:country=>["can't be blank"]}>

Many to many database

This is probably basic stuff, but I really made my homework looking it up. I still can´t find the solution.
I have a users db, a movies db, and a ratings db. Ratings has a movie_id, user_id and grade.
class Rating < ActiveRecord::Base
attr_accessible :grade
belongs_to :user
belongs_to :movie
end
class User < ActiveRecord::Base
has_many :ratings, :dependent => :destroy
has_many :movies, :through => :ratings
...
class Movie < ActiveRecord::Base
has_many :ratings, :dependent => :destroy
has_many :users, :through => :ratings
...
But I can´t create a rating with both movie_id and user_id
rails c test
Loading test environment (Rails 3.0.3)
#movie=Factory(:movie)
#<Movie id: 1, title: "Rocky 20", link: "#", created_at: "2011-01-22 21:04:42", updated_at: "2011-01-22 21:04:42">
#user=Factory(:user)
#<User id: 1, name: "lola", email: "lola#gmail.com", created_at: "2011-01-22 21:04:48", updated_at: "2011-01-22 21:04:48", encrypted_password: "c306a696138fa08c543ada3a3b4fd92067e9941743b7558e891...", salt: "f82c6abaccec17e2866d50150ad200181eb4bc8e0204249f171...", admin: false>
>> #user.ratings.create(:grade=> 4, :movie_id =>#movie.id)
=> #<Rating id: 1, grade: 4, user_id: nil, movie_id: nil, created_at: "2011-01-22 21:04:55", updated_at: "2011-01-22 21:04:55">
that "movie_id: nil" is what is killing me...
then of course me tests are not passing:
#user.rating.create(grade => 5, :movie_id => #movie.id) has no movie_id
#movie.rating.create(grade => 5, :user_id => #user.id) has no user_id
any hints?
Thanks!!
The code you're showing here should absolutely work IMO. Which leaves me guessing that it's something you aren't showing here. A couple of things I'd try:
Use the regular console for a change
Don't use Factories (maybe it's them?), create actual entries instead
I've tried your example and here's what I got:
> m = Movie.create :title => "Foo"
=> #<Movie id: 1, title: "Foo", created_at: …>
> u = User.create :name => "Marc"
=> #<User id: 1, name: "Marc", created_at: …>
> u.ratings.create :grade => 4, :movie_id => m.id
=> #<Rating id: 1, grade: 4, user_id: 1, movie_id: 1, created_at: …>
> m.ratings.create :grade => 3, :user_id => u.id
=> #<Rating id: 2, grade: 3, user_id: 1, movie_id: 1, created_at: …>
Which you can also use like this, as you might know:
> m.ratings.create :grade => 3, :user => u
=> #<Rating id: 3, grade: 3, user_id: 1, movie_id: 1, created_at: …>
Try defining your factories like this:
Factory.define :movie, :class => Movie do |f|
f.title "Rocky 20"
f.link "#"
end
Factory.define :user, :class => User do |f|
f.name "Lola"
f.email "lola#gmail.com"
end
Factory.define :rating, :class => Rating do |f|
f.movie { |m| m.association :movie}
f.user { |u| u.association :user}
f.grade 4
end
Then to test a rating, use the rating factory by itself:
it "creates a rating" do
rating = Factory.create(:rating)
rating.user.name.should == "Lola"
rating.movie.title.should == "Rocky 20"
end

Resources