Store multiple tasks for a job in Rails 4 - ruby-on-rails-4

I'm developing an application using Ruby on Rails 4 that has a list of pre-defined tasks that can be added into a job. The job can have one or more tasks assigned to it. How do I store the tasks in the job object? Would this be through an array of some sort? What would that look like?
I imagine this would work like a tokenfield or even a selectable list. Maybe checkboxes (but that may get unwieldy).
app/models/job.rb
class Job < ActiveRecord::Base
has_paper_trail
has_many :tasks
end
app/models/task.rb
class Task < ActiveRecord::Base
has_paper_trail
belongs_to :job
end
Tasks Table - just a sample
id | name | description
1 | Clean Room | Pick up toys
2 | Dust Shelf | Use dusting rag

It depends on whether you need to be able to assign the same task to multiple jobs. This will mean either a has_many :tasks or a has_many :tasks, through: :task_assignments association on the Job model. If you need further guidance on using these associations, have a look at the Rails Guides Association Basics guide.
As for the controller and view components, I suggest you have a look at the Rails Guides Form Helpers guide, and perhaps also watch Railscasts episodes on handlign nested forms: #196 - Part 1 and #197 - Part 2.

Related

NoMethodError - new since upgrading to Rails 4

I'm at my wit's end. I upgraded to Rails 4.2.10, and everything is terrible.
Here is the relevant part of /models/product.rb
class Product < ActiveRecord::Base
delegate_attributes :price, :is_master, :to => :master
And here is /models/variant.rb:
class Variant < ActiveRecord::Base
belongs_to :product
The variants table has fields for "price" and "is_master". Products table does not.
It used to be the case that one could access Product.price and it would get/set the price for the master variant (there's really only one variant per product, the way things are currently set up).
Now it complains that:
NoMethodError: undefined method `price=' for #<Product:0x0000000d63b980>
It's true. There's no method called price=. But why wasn't this an issue before, and what on earth should I put in that method if I create it?
Here's the code to generate a product in db/seeds.rb:
product = Product.create!({
name: "Product_#{i}",
description: Faker::Lorem.sentence,
store_id: u.store.id,
master_attributes: {
listing_folder_id: uuids[i],
version_folder_id: uuids[i]
}
})
product.price = 10
product.save!
end
delegate_attributes isn't a Rails method and looks like it comes from a gem (or gems) that aren't actively maintained?
If there's a new version of whatever gem you're using that might help, because the short answer is that part of the "delegating" of an attribute would involve getting and setting the attribute, so it would generate #price= for you.
If you want to define it yourself, this should do it (within your Product class):
def price=(*args)
master.price=(*args)
end
or if you want to be more explicit:
def price=(amount)
master.price = amount
end

How do I get a set of objects belonging to another set of objects in Rails 4 ActiveRecord?

If I have two models, say, an user Model and a Company model like those defined below. How do I get all of the companies of a set of users?
class User < ActiveRecord::Base
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :users
end
users = User.where(:state => "Florida")
From this, I need a variable that holds all of the companies belonging to those users
companies = users.?
Do I need to loop through each of the users and add them to an array? I'm guessing there is a better way to do this. Any help is appreciated.
You can do this
Company.includes(:users).where(users: { state: 'Florida' })
BUT Taking into account http://guides.rubyonrails.org/ recommendations
It will be more correct to do
Company.joins(:users).where(users: { state: 'Florida'})
This does INNER JOIN instead of LEFT OUTER JOIN

Delete an element from ActiveResource::Collection relationship

I have many-to-many relationship (HABTM) in a file service:
class Album < ActiveRecord::Base
has_and_belongs_to_many :media, join_table: 'albums_media'
end
class Medium < ActiveRecord::Base
has_and_belongs_to_many :albums, join_table: 'albums_media'
end
We have a gem containing the ActiveResource interface classes into that service:
class Medium < ActiveResource::Base
...
def albums
Album.where(id: album_ids)
end
end
I can easily create a Medium that belongs to a given Album by passing album_ids:
album = Album.create(...)
medium = Medium.create(album_ids: [album.id])
I'd like to be able to delete a certain medium from a given album, but ActiveResource doesn't really support this directly.
# not supported...
medium.albums.destroy(...)
And I'd rather not use has_many :through as I don't really need to manage the join directly other than doing this kind of thing.
Any insight is appreciated.
FYI: I ended up adding the extra "join" resource in the file service itself, and then adding the corresponding ActiveResource class to the gem. Now we can simply manage the joins directly using the API.
It was more work than I wanted to do but AR is appropriately lite weight and doesn't support many-to-many relationships. The point is, it can be done.

Eager Loading Multiple Associations and serialization

In my project I have 3 models Assignment, Question and MultipleChoice with the following associations
assignment.rb
has_many :questions, dependent: :destroy
question.rb
belongs_to :assignment, class_name: 'Assignment', foreign_key: :assignment_id
has_many :multiple_choices, dependent: :destroy
multiple_choice.rb
belongs_to :question
Now I want to make a query like below
#assignment = Assignment.find(params[:id])
#questions = #assignment.questions.includes(:multiple_choices)
This is not working as expected.
So, I want all questions that belongs to the assignment for the params[:id] and the associated multiple choices that belongs to a question. My above query do not give any error but it only show questions not multiple choices associated with question. How can I do this? I am learning api development for rails. So I want to send this value as json and probably I will need serialization. How can I do this? I am working on rails 4.
Edit
well the output for
#questions = #assignment.questions.includes(:multiple_choices) and
#questions = #assignment.questions.eager_load(:multiple_choices) and
#questions = #assignment.questions are all same.
I dont understand why the output do not include any value from multiple choices table
Output of the command
#assignment.questions.eager_load(:multiple_choices).to_sql id
=> "SELECT \"questions\".\"id\" AS t0_r0, \"questions\".\"content\" AS t0_r1, \"questions\".\"q_type\" AS t0_r2, \"quest
ions\".\"created_at\" AS t0_r3, \"questions\".\"updated_at\" AS t0_r4, \"questions\".\"assignment_id\" AS t0_r5, \"multi
ple_choices\".\"id\" AS t1_r0, \"multiple_choices\".\"content\" AS t1_r1, \"multiple_choices\".\"created_at\" AS t1_r2,
\"multiple_choices\".\"updated_at\" AS t1_r3, \"multiple_choices\".\"question_id\" AS t1_r4 FROM \"questions\" LEFT OUTE
R JOIN \"multiple_choices\" ON \"multiple_choices\".\"question_id\" = \"questions\".\"id\" WHERE \"questions\".\"assignm
ent_id\" = $1"
The behaviour for includes function changed in Rails 4. You can find more details here:
http://blog.arkency.com/2013/12/rails4-preloading/
I also suppose, that if you will use eager_load instead of includes, you will get the result you need.
#assignment is an object from which you are getting the questions.
But with #questions = #assignment.questions.includes(:multiple_choices) how can you get the multiple_choices without calling this on an object?
Try this->
#assignment = Assignment.includes(:questions).find(params[:id])
#assignment.questions.includes(:multiple_choices).collect {|question| question.multiple_choices }
This also includes eager loading.
Hope you'll get what you expect.

Rails 4: strong_params,nested_attributes_for and belongs_to association trouble

I really can't get my head around Rails 4 strong parameters, belongs_to association and form with fields_for.
Imagine I have model for quoting some price:
class Quote < ActiveRecord::Base
belongs_to :fee
accepts_nested_attributes_for :fee
Now, I have seeded some fees into the db, and have put some radiobuttons on my form_for #quote using fields_for. The values of the radiobuttons are simply ids of the records.
Here is the troubling part, the controller:
def create
#quote = Quote.new(quote_params)
...
end
def quote_params
params.require(:quote).permit(:amount_from, fee_attributes: [:id])
end
From my understanding, automagically Rails should fetch fee record with some id, but there is some mystic error instead.
params hash is: "quote"=>{"amount_from"=>"1200", "fee_attributes"=>{"id"=>"1"}}
Log tail:
Completed 404 Not Found in 264ms
ActiveRecord::RecordNotFound (Couldn't find Fee with ID=1 for Quote with ID=)
app/controllers/quotes_controller.rb:14:in `create'
I really don't understand what is going on here, have read Rails association guide, googled for hour for all info, but to no avail.
What I want to achieve here is to understand the correct "Rails way" to fetch some associations for new Quote object using some params I've put in the form.
Guess I got nested_attributes_for wrong, somehow thought it would call Fee.find automagically.
I've opted for ditching fields_for helpers from the form and rendering fields manually like
radio_button_tag 'fee[id]', fee.id
Then in controller I have 2 params methods now:
def quote_params
params.require(:quote).permit(:amount_from)
end
def fee_params
params.require(:fee).permit(:id)
end
And my action looks like
def create
#quote = Quote.new(quote_params)
#quote.fee = Fee.find(fee_params[:id])
...
Any additions on best practices when one has to handle lots of different objects with not so straight init logic are welcome.