rails using has_many and belongs_to - ruby-on-rails

Alright, I'm going to try to explain this as best as possible:
I have two models
employer.rb
class Employer < ActiveRecord::Base
has_many :listings
end
listing.rb
class Listing < ActiveRecord::Base
belongs_to :employer
end
Employers login through the employers_controller and listings are created through listings_controller
I'm having trouble getting the id from the employer table being inserted into the employer_id column in each individual created listing. I hope this makes sense. If anyone has any advice, it would be much appreciated. I have a feeling this is because I'm doing this outside of the employer_controller, but not sure.
Thanks!

1) If you are not dealing as nested resource then
When you render the new action of Listing controller, you know for which employer (#employer) you want to create the listing.
So render a hidden field for employer_id using a hidden_field or hidden_field_tag
hidden_field_tag 'employer_id', #employer.id()
2) If you are dealing as nested resource and your route looks something like
/employers/:employer_id/listings/new / (Get) && /employers/:employer_id/listings
Then in create action
#employer = Employer.find(params[:employer_id])
#employer.Listing.new(params[:listing]

I think you have the employer id in your session, since they need to login to create the listing. I won't use the param from the view, then its easy for one employer to create a listing as if it was created by another employer, just by changing the id value in your hidden field. Here's what is possibly a better approach:
#employer = Employer.find(current_user.id)
#employer.Listing.new(params[:listing]

Related

How can I get and use the id of an object from post_params before saving

I have 3 models.
User - has many comments
ISBN (of a book) - has many comments
Comment - belongs to User, belongs to Book
In my comment form, I have;
Comment,
user (will be hidden)
ISBN
When I submit the form, I want to check the db for the presence of 'isbn'
if yes, add comment, else if the isbn doesn't exist yet, create it and add the comment.
At the moment I can find the existence using:
def create
if Isbn.exists?(isbn_number: comment_params[:isbn_id])
create comment
else
create isbn
create comment
save
end
end
This saves the isbn number as the isbn_id which is not what I want.
Any help would be greatly appreciated.
I would probably solve this by finding or creating the association to the Isbn model in a callback block upon save. It could be done like this.
Note that I am using :isbn_number in the params instead of :isbn_id.
class Comment < ActiveRecord::Base
belongs_to :user
belongs_to :isbn
attr_accessor :isbn_number
before_save do
if #isbn_number.present?
self.isbn = Isbn.where(isbn_number: #isbn_number).first_or_create!
end
end
end

Ruby on Rails: Accept nested attributes for parent rather than child records?

In my Rails app Users can have many People which in turn can (but don't have to) belong to Organisations.
In short, this:
Users --< People >-- Organisations
Now, it would be nice to be able to create new organisations from within a people view somehow. It tried this:
class Person < ActiveRecord::Base
attr_accessible :name, :organisation_attributes
belongs_to :user
belongs_to :organisation
accepts_nested_attributes_for :organisation
end
But it's not working because Organisation is not a child of Person.
Is there another way to realise this?
Thanks for any help.
I can see that Person is actually a child of Organisation and its possible to make nested form for parent model also. And you are already using accepts_nested_attributes_for.
Im assuming that you want to show a Organisation form for a already saved person. Then
In your PeopleController#show method build the organisation
#person.build_organisation
And in people/show.html.erb
form_for(#person) do |f|
f.fields_for(:organisation) do |fo|
# show the fields of organisation here.
end
end
It should work.
Update:
I tried something similar and it worked :) Ive made a gist including the snippets.
Please follow the link https://gist.github.com/3841507 to see it working.

Rails associations / sessions question

I am working on a app for my kids to log their chores. I have 3 children (Nick, Siena, Mac) and have a home page with each name hyperlinked ...
I have the following associations:
Child:
has_many :completions
has_many :chores, :through=>:completion
Completion:
belongs_to :child
belongs_to :chore
Chore:
has_many :completions
has_many :kid, :through=>:completion
How do I (upon clicking the child's name) save the child_id as a session object for posting completions to the completions models?
How do I clear / change that sesison to a new child when another child clicks their name in the homepage?
Any help is greatly appreciated. Thanks, CB
So josh went above and beyond. As a noob i was asking something much more simple and elementary for most folks. The answer was quite simple:
ApplicationController
private
def current_child
child = Child.find(params[:id])
session[:child_id] = child.id
end
end
This allowed me to store that child's id in a session and post to the completed model.
If I understand the question correctly (at least as described in your comment), I did something similar recently. See Building a nested attribute from multiple parent objects. Basically, I used polymorphic_url to make a link to create a new item (I would probably use #child.chores.build(params)) and pass the attribute :chore_id, i.e.
link_to "Mark as complete", polymorphic_url([:new, #child, :completion], :chore_id => #chore.id)
In your controller make sure that for your ChoresController#new you have something like
def new
#chore = <current_child>.chores.build(params)
end
Hope this helps.

Rails 3 Polymorphic Associations Question

I've been trying to switch my Orders model to a polymorphic association with my Product and Service models. However, I have a few questions that I haven't been able to find answers to, even after watching the RailsCast and reading the documentation (so, those suggestions are appreciated, but I need a more concrete answer).
Question:
Is a polymorphic association the best thing to use in this case? Prior to this, I was using a Transaction model that had multiple belongs_to associations and used a custom Parent function to determine which one it was. This was working fine, but someone suggested a polymorphic association may clean things up.
I set up the polymorphic association properly and have been unable to have the transactable_id and transactable_type automatically populated. The code is below. I have side-stepped this by manually putting them in inside the form, but if anyone knows the proper way to do it, that would be great!
How can I access elements with polymorphic associations? For example, in my Cart object (which has_many Transactions and which Transactions belongs_to) I can no longer access things using #cart.transactions.each do |t| ... #t.product.name type coding.
My model associations look like this:
class Order < ActiveRecord::Base
belongs_to :orderable, :polymorphic => true
end
class Product < ActiveRecord::Base
has_many :orders, :as => :orderable
end
My forms used to look like this:
<% form_for [#orderable, #order] do |f| %>
...
<% end %>
And were rendered like this in my Product Show view:
<%= render 'orders/form' %>
Now, I pass a variable for the product.id in the render partial and use it to populate the transactable_id field. But, I feel like that is very messy.
Again, I have read the tutorials and API docs and have been unable to solve this, so any help would be greatly appreciated!!
Answers to your questions:
If your business login implies that multiple models will have related model with the same fields so you should use polymorphic association. (In your case you can use it).
If set up polymorphic association Rails will automatically handle setting *_id and *_type fields depending on associated parent model.
Lets say you have Product with many orders in polymorphic association and you want to define which model order belongs to:
order = Order.first
order.orderable

Best practice: How to split up associations-functions in controllers with equal-access models

I have 2 equal-access models: Users and Categories
Each of these should have the standard-actions: index, new, create, edit, update and destroy
But where do I integrate the associations, when I want to create an association between this two models?
Do I have to write 2 times nearly the same code:
class UsersController << ApplicationController
# blabla
def addCategory
User.find(params[:id]).categories << Category.find(params[:user_id])
end
end
class CategoriessController << ApplicationController
# blabla
def addUser
Category.find(params[:id]).users << User.find(params[:user_id])
end
end
Or should I create a new Controller, named UsersCategoriesController?
Whats the best practice here? The above example doens't look very DRY.... And a new controller is a little bit too much, I think?
Thanks!
EDIT:
I need to have both of these associations-adding-functions, because f.e.
#on the
show_category_path(1)
# I want to see all assigned users (with possibility to assign new users)
and
#on the
show_user_path(1)
#I want to see all assigned categories (with possibility to assign new categories)
EDIT:
I'm taking about a HBTM relationship.
If you have a situation where you need to do this with has_and_belongs_to_many, you could take the approach you are currently using, or you could build this into your existing update actions.
When you add a habtm relationship, you will get an additional method on your classes...
class User < ActiveRecord::Base
has_and_belongs_to_many :categories
end
With this, you can do this:
user = User.find(params[:id])
user.category_ids = [1,3,4,7,10]
user.save
The categories with those ids will be set. If you name your form fields appropriately, the update can take care of this for you if you want to use checkboxes or multiselect controls.
If you need to add them one at a time, then the methods you've built in your original post are reasonable enough. If you think the repetition you have is a code smell, you are correct - this is why you should use the approach I outlined in my previous answer - an additional model and an additional controller.
You didn't mention if you are using has_and_belongs_to_many or if you are using has_many :through. I recommend has_many :through, which forces you to use an actual model for the join, something like UserCategory or Categorization something like that. Then you just make a new controller to handle creation of that.
You will want to pass the user and category as parameters to the create action of this controller.
Your form...
<% form_tag categorizations_path(:category_id => #category.id), :method => :post do %>
<%=text_field_tag "user_id" %>
<%=submit_tag "Add user" %>
<% end %>
Your controller...
class CategorizationsController < ApplicationController
def create
if Categorization.add_user_to_category(params[:user_id], params[:category_id])
...
end
end
then your categorization class...
class Categorization
belongs_to :user
belongs_to :category
def self.add_user_to_category(user_id, category_id)
# might want to validate that this user and category exist somehow
Categorization.new(:user_id => user_id, :category_id => category_id)
Categorization.save
end
end
The problem comes in when you want to send the users back, but that's not terribly hard - detect where they came from and send them back there. Or put the return page into a hidden field on your form.
Hope that helps.

Resources