Having trouble posting from a child to a parent's other child:
Can this be done like I want, post from the child (Order) to the Parent's (User's) other child (Customer) or do you have to go at this from some other angle?
I have 3 Models:
class User
has_many :orders
has_one :customer, dependent: :destroy
accepts_nested_attributes_for :customer
class Order
belongs_to :user
belongs_to :project
class Customer
belongs_to :user
I've tried accepts_nested_attributes_for :orders from the user, I've also tried accepts_nested_attributes_for :user from the order
neither seem to work,
Hers my form:
= form_for #order do |f|
= f.hidden_field :user_id
= f.fields_for :user do |user|
= user.fields_for :customer do |customer|
= customer.hidden_field :customer_attribute
I am not sure this is possible. Anyway you certainly forgot to add
accepts_nested_attributes_for :user
in your Order class.
Related
I'm stucked in the way to do this task on Rails 5.
I need to "mass" edit a relation between a Project and it's Members
In the UI, I open a popup with a certain list of members (a list of User) and those member have or have not belongs to the Project (check the relations down here).
I need to have the ability to mark some of them (who not belongs to) or unmark others (who belongs to) with checkbox's and "save" the form and create/delete the relations.
For the record I have this models
// project.rb
class Project < ApplicationRecord
has_many :memberships, dependent: :destroy, class_name: 'ProjectMember'
has_many :members, through: :memberships, class_name: 'User', source: :user
end
// project_member.rb
class ProjectMember < ApplicationRecord
belongs_to :user
belongs_to :project
end
// user.rb
class User < ApplicationRecord
has_many :project_members
has_many :projects, through: :project_members
end
I'm kinda new on Rails and I'm really stucked in the way to create the forms (using SimpleForms) and how to edit the relation.
What's the correct approach? I tried to find over the web without success :(
I hope my question it's clear enough :)
I think the helpers you want are included in the gem cocoon : https://github.com/nathanvda/cocoon
Using this gem, your view for the project edition would look like this :
projects/_form
= simple_form_for #project do |f|
-# your project fields...
%h3 Members
#members
= f.simple_fields_for :members do |member|
= render 'member_fields', f: member
.links
= link_to_add_association 'add member', f, :members
= f.submit
projects/_member_fields
.nested-fields
= f.association :user
= link_to_remove_association "remove user from project", f
Edit : I focused on the view part, but before that, in the model, you have to accept nested attributes from forms :
class Project < ApplicationRecord
has_many :memberships, dependent: :destroy, class_name: 'ProjectMember'
has_many :members, through: :memberships, class_name: 'User', source: :user
accepts_nested_attributes_for :members, reject_if: :all_blank, allow_destroy: true
end
There's also a bit of work to do in the controller to permit the nested attributes.
def project_params
params.require(:project).permit(:name, :description, members_attributes: [:id, :user_id, :_destroy])
end
I have a User model and a Book model joined with a Like model.
class Book < ActiveRecord::Base
belongs_to :user
# the like associations
has_many :likes
has_many :liking_users, :through => :likes, :source => :user
class User < ActiveRecord::Base
has_many :books
# the like associations
has_many :likes
has_many :liked_books, :through => :likes, :source => :book
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :book
I want to add an attribute to the Like model so while right now a User can Like a book to add it to their profile, I want the User to be able to write a recommendation.
I generated the attribute Recommendation:text to the Like (joining) model, but am unsure how to add this to views so a User can write a recommendation that will be tied to the Like (and thus that book and user).
I'm looking at this post - Rails has_many :through Find by Extra Attributes in Join Model - which describes something similar but does not explain how to implement this in the views.
Let me know if you can point me in the right direction. Thanks!
I think you should create a separate model for this Recommendation, dependent of the Like model:
class Book < ActiveRecord::Base
belongs_to :user
has_many :comments
has_many :commenters, :through => :comments, :source => :user
class User < ActiveRecord::Base
has_many :books
has_many :comments
has_many :commented_books, :through => :comments, :source => :book
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :book
Then, the logic to create a comment for a book:
# Books Controller
def show
#book = Book.find(params[:id])
#comment = #book.comments.build
end
# show view of the book
form_for #comment do |form|
form.hidden_field :user_id, value: current_user.id
form.hidden_field :book_id
form.text_area :content # the name of the attribute for the content of the comment
form.submit "Post comment!"
end
To list all the comments of a specific User:
# users controller (profile page)
def show
#user = User.find(params[:id])
end
# show view of Users
#user.comments.includes(:book).each do |comment|
"Comment on the book '#{comment.book.name}' :"
comment.content
end
I suppose that the like functionnality works with ajax ? (remote: :true or in pure javascript)
You can append a form with the response of your request with the id of the new like, and again handle the recommendation by an ajax request
I have a Rails 4 app, with models Challenge and ChallengeList. It's a many-to-many relationship, so I also have a join table with model ChallengeListsChallenge. I defined this last model because I want my ChallengeLists to be ordered lists, and so used it to exploit acts_as_list:
class ChallengeList < ActiveRecord::Base
has_many :challenge_lists_challenges, :dependent => :destroy
has_many :challenges, :through => :challenge_lists_challenges
accepts_nested_attributes_for :challenges
end
class ChallengeListsChallenge < ActiveRecord::Base
default_scope :order => 'position'
belongs_to :challenge
belongs_to :challenge_list
acts_as_list :scope => :challenge_list
end
This works fine.
In my HTML, I have a form that allows the user to define a new ChallengeList. It has a nested form for Challenges:
= f.fields_for :challenges do |challenge_builder|
.field
= challenge_builder.text_field :description
But I would also like the user to be able to change the position. So I thought I'd be smart, add a field for position:
= challenge_builder.text_field :position
Of course, this doesn't work, because 'position' is set on join items, not Challenge items.
Having a nested form for ChallengeListsChallenges would give me access to the position, but is not cool because:
I need a reference to my ChallengeList id (which is not insurmountable, but not pretty either)
I can only reference existing Challenge ids
So what can I do?
Like in this question:
Set up model dependencies like so:
class ChallengeList < ActiveRecord::Base
has_many :challenge_lists_challenges, :dependent => :destroy
has_many :challenges, :through => :challenge_lists_challenges
accepts_nested_attributes_for :challenge_lists
end
class ChallengeListsChallenge < ActiveRecord::Base
default_scope :order => 'position'
belongs_to :challenge
belongs_to :challenge_list
acts_as_list :scope => :challenge_list
accepts_nested_attributes_for :challenges
end
And a doubly nested form like so:
= form_for #challenge_list do |f|
= f.fields_for :challenge_lists_challenges do |links_form|
.field
= links_form.number_field :position
%br/
= links_form.fields_for :challenge do |challenge_form|
.field
= challenge_form.text_field :description
= challenge_form.text_field :id
And it should work.
**Updated
I have the following models:
product.rb
class Product
belongs_to :user
has_many :line_items
has_many :orders, :through => :order_products
has_many :order_products
lineitem.rb
class LineItem
belongs_to :product
belongs_to :cart
belongs_to: order
order.rb
class Order
belongs_to :user
belongs_to :product
has_many :purchases
has_many :line_items, :dependent => :destroy
has_many :orders, :through => :order_products
has_many :order_products
accepts_nested_attributes_for :order_products
order_product.rb
class OrderProduct < ActiveRecord::Base
belongs_to :order
belongs_to :product
end
order_controller.rb
if #order.save
if #order.purchase
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
The above are my association for the models. I have a big problem in storing multiple product_id from line_items after the cart has been purchased.
I believe there should be codes after if#order.purchase for it to work. How am I suppose to store the order_id and product_id into order_products table.
Can anyone assist me on this?
Appreciate any help here. Thanks
It looks like you might benefit from learning about accepts_nested_attributes_for, as well as how foreign_keys work with ActiveRecord
Foreign Keys
If you set up your ActiveRecord associations correctly, you'll be able to call something like #product.line_items from a single call
ActiveRecord (& relational databsaes in general) work off foreign_keys, which are basically a reference to a model's id in another table. When you say you want to input order_id in another table, what you really need to look at is how to get ActiveRecord to put the correct foreign key into the record
The reason why I'm writing this is because if you can appreciate how ActiveRecord works, you'll be in a much stronger position to fix your problem
Accepts_Nested_Attributes_For
I believe the function that will help you is accepts_nested_attributes_for - which basically allows you to save another model's data through your current model
It works like this:
#/app/models/order.rb
class Order
belongs_to :user
belongs_to :product
has_many :purchases
has_many :line_items, :dependent => :destroy
has_many :orders, :through => :order_products
has_many :order_products
accepts_nested_attributes_for :order_products
This means that if you send the appropriate nested attributes to this model, it will process :order_products for you
To do this, you need to add this to your form & controller:
#app/controllers/orders_controller.rb
def new
#order = Order.new
#order.order_products.build
end
private
def strong_params
params.require(:order).permit(:standard_params, order_products_attributes: [:name] )
end
#app/views/orders/new.html.erb
<%= form_for #order do |f| %>
<%= f.fields_for :order_products do |product| %>
<%= product.text_field :name %>
<% end %>
<% end %>
I am trying to do an update_attributes of a nested model and keep running into a mass assignment error. Here are my models:
class Lineup < ActiveRecord::Base
belongs_to :user
has_many :piece_lineups
has_many :pieces, through: :piece_lineups
accepts_nested_attributes_for :piece_lineups
end
class Piece < ActiveRecord::Base
attr_accessible :cost, :description, :name, :category
has_many :piece_lineups
has_many :lineups, through: :piece_lineups
end
class PieceLineup < ActiveRecord::Base
attr_accessible :piece
belongs_to :piece
belongs_to :lineup
end
User has_one lineup by the way. So I thought that by adding accepts_nested_attributes_for to the lineup model that it would work but it is not. Here's my form:
- #lineup.piece_lineups.build(:piece => piece)
= form_for(#lineup) do |f|
= f.fields_for :piece_lineups do |piece_lineup|
= piece_lineup.hidden_field(:piece_id, :value => piece.id)
= f.submit
and my Lineup controller action:
def update
#lineup = current_user.lineup
#lineup.update_attributes(params[:lineup])
and finally, the error:
Can't mass-assign protected attributes: piece_lineups_attributes
What am i missing here? Thanks!
accepts_nested_attributes_for creates an attribute writer -- in your case, piece_lineups_attributes= -- for passing attributes to another model. So, you need to add attr_accessible :piece_lineups_attributes to your Lineup model to make it mass-assignable.
UPDATE
There is a better way of going about this.
If you add attr_accessible :piece_ids to your Lineup model, then change your view to
= form_for(#lineup) do |f|
= f.hidden_field(:piece_ids, :value => piece.id)
= f.submit
You don't need nested attributes at all.
Mass Assignment usually means passing attributes into the call that creates an object as part of an attributes hash. So add piece_lineup's fields to your list of attr_accessors for that model, OR try this:
#lineup = current_user.lineup
#lineup.piece_id = params[:piece_id]
#lineup.save
Also see:
http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html