Model Relationships - ruby-on-rails

So I am building this ruby on rails webapp. I have two models: Courses and lessons. Courses has many lessons and lesson belongs to course. I have the forms running just fine but what i want to do is pass the :course_id to the lesson form to be able to keep track of what course the lesson belongs to. ( I have included a course_id value in the lesson table.
Basically, my question is how can i pass the :id of the course onto the lesson form?

Why not just assign the new lesson the course id?
Instead of doing
#lesson = Lesson.new
do
#lesson = Course.find(params[:course_id]).lessons.new
or something of that sort.
Or (better):
#lesson = Course.find(params[:course_id]).lessons.build

A hidden field?
Not sure what you want to do with this course_id in the form, but if it's just to pass it back on submit, look into Nested Resources

Related

How does one actually use a has_many/belongs_to relationship?

My two models are User has_many :books and Book belongs_to :user.
The users table has only the column name, while the books table has users_id and title.
Is this how I'm actually supposed to use them? With the users table populated, how do I go about adding a book with a specific user, done by searching their name and not the ID column? I know this is a simple thing, but I really cannot find it on Google, or by re-reading my books and re-watching my Lynda videos; I know the information must be in there somewhere but it is completely frying my brain right now, and I'm extremely confused. I'm very used to SQL and learning to use ActiveRecord instead feels like trying to write with my left hand.
What I want to do is the equivalent of, in SQL, INSERT INTO books (title, users_id) VALUES ("Wolves of the Calla", (SELECT id FROM users WHERE name = 'Sarah'));.
Find the user with the given name and then use the association to create a book with the found user_id
user = User.where(:name => "Sarah").first
user.books.create(:title => "Wolves of the Calla")
As explained in the Association Basics Guide, you'd need something like this:
createdBook = #user.books.create(title: "Wolves of the Calla")
This can all be found in the Rails Documentation. Its worth a read, if you haven't done so already.
In regards to this question:
...how do I go about adding a book with a specific user...
There are a number of ways you can do it, but the key thing to remember is that the has_many and belongs_to methods "create" association methods for you. In this way you can retrieve, and add to an object's associations; Rails will take care of handling the foreign keys and such, so long as they are named in accordance with its naming convention (which it seems you have done)
So as a simple example, to add a book to a user's collection of books, would be something like this:
#user = User.where(name: "Sarah").first
#user.books.create(title: "Wolves of the Calla")
#Rails 4 syntax
#Approach 1
#user = User.find_by(name: 'Sarah')
#book = #user.books.create(title: 'Wolves of the Calla')
#Alternatively
#user = User.find_by(name: 'Sarah')
#user.books << Book.create(title: 'Wolves of the Calla')
#Alternatively
#user = User.find_by(name: 'Sarah')
#book = Book.create(title: 'Wolves of the Calla')
#user.book_ids += [#book.id]

How to add new object of model in a foreign controller

I am rather new to Rails.
I am working on a profile-page for a User. The show view is divided into partials. The thing about my modelling structure is, that a User can have a Skill. But the User model itself does not have a Skill related column, so all Skill entries are saved in the Skill model.
So, my question is, how can I include a partial into the User show view, that contains a simple add Skill form (name needed only), which saves that Skill into its own table and adds it to the collection of the current User.skills?
in User#show create a #skill = Skill.new which you can use in your views.
then in you partial you can do
<%= form_for(#skill), ... %>
see more at http://guides.rubyonrails.org/form_helpers.html
I dont understand your problem. You could define a form in the partial and in the controller's action you would have to simply save the Skill and associate the user's id to it. I hope you know that the the Skill model must belong_to User and there should be a user_id column in the skills table to create the association. Even though I am writing a sample code for creating association below.
skill = Skill.new
user.skill << skill #Add association for user and skill
#Add skill related info from params into the skill model object
skill.save!
If you have the partial o the form at skill/_form.html.erb you can do:
<%= render "skills/form", skill: #skill %>
on the view, and you must add
#skill = Skill.new
on the show action of your Profile controller. To save that skill, you must do that on your update action on the Profile controller:
#skill = Skill.create(params[:skill])
#user.skills < #skill
#user.save

Update one model and create other model in one form Rails 3.2.5

I have one form that can create two models perfectly, but, is there any way to update one of the models and create the other?
Resuming:
I have a form for creating an appointment and also I can create the person for this appointment.
def new
#Cita = Cita.new
#Cita.build_paciente
render :new
end
def create
#Cita = Cita.new(params[:cita])
if #Cita.save
redirect_to :action => 'hoy'
else
render 'new'
end
This is working pretty well when I create the two models at time, but if I fill the person fields ...
How can I do for UPDATING the person attributes ("paciente") and creating the appointment ("Cita") for that person.
Thanks.
Finally I solved it adding a hidden field filling the person_ID on the person form. When you send the ID in the model attributes rails makes an update instead of an insert for that model while creates the other model associating the nested model.
If this hidden field is empty, rails create the two models at time.

has_many through blowing away the association's metadata on mass association

Hey,
Not a Rails noob but this has stumped me.
With has many through associations in Rails. When I mass assign wines to a winebar through a winelist association (or through) table with something like this.
class WineBarController
def update
#winebar = WineBar.find(params[:id])
#winebar.wines = Wine.find(params[:wine_bar][:wine_ids].split(",")) // Mass assign wines.
render (#winebar.update_attributes(params[:wine_bar]) ? :update_success : :update_failure)
end
end
This will delete every winelist row associated with that winebar. Then it finds all of the wines in wine_ids, which we presume is a comma separated string of wine ids. Then it inserts back into the winelist a new association. This would be expensive, but fine if the destroyed association rows didn't have metadata such as the individual wine bar's price per glass and bottle.
Is there a way to have it not blow everything away, just do an enumerable comparison of the arrays and insert delete whatever changes. I feel like that's something rails does and I'm just missing something obvious.
Thanks.
Your problem looks like it's with your first statement in the update method - you're creating a new wine bar record, instead of loading an existing record and updating it. That's why when you examine the record, there's nothing showing of the relationship. Rails is smart enough not to drop/create every record on the list, so don't worry about that.
If you're using the standard rails setup for your forms:
<% form_for #wine_bar do |f| %>
Then you can call your update like this:
class WineBarController
def update
#winebar = WineBar.find(params[:id])
render (#winebar.update_attributes(params[:wine_bar]) ? :update_success : :update_failure)
end
end
You don't need to explicitly update your record with params[:wine_bar][:wine_ids], because when you updated it with params[:wine_bar], the wine_ids were included as part of that. I hope this helps!
UPDATE: You mentioned that this doesn't work because of how the forms are setup, but you can fix it easily. In your form, you'll want to rename the input field from wine_bar[wine_ids] to wine_bar[wine_ids_string]. Then you just need to create the accessors in your model, like so:
class WineBar < ActiveRecord::Base
def wine_ids_string
wines.map(&:id).join(',')
end
def wine_ids_string= id_string
self.wine_ids = id_string.split(/,/)
end
end
The first method above is the "getter" - it takes the list of associated wine ids and converts them to a string that the form can use. The next method is the "setter", and it accepts a comma-delimited string of ids, and breaks it up into the array that wine_ids= accepts.
You might also be interested in my article Dynamic Form Elements in Rails, which outlines how rails form inputs aren't limited to the attributes in the database record. Any pair of accessor methods can be used.

Rails Foreign Key Issue

Sorry if this question seems simple, I am very very new to Rails (just started learning a few days ago), but after consulting Google and "Agile Web Development with Rails" I can't find the answer.
I have an issue with Rails 2.3.8 creating a foreign key on two models. My tables look like this:
cars manufacturer
---- ------------
car_make name
car_model country
car_class logo_url
image_url (and default 'id' created by Rails)
manufacturer_id
(and default 'id' created by Rails)
My 'car_make' and 'name' fields are essentially the same; every Car I create, I want to be able to associate it with an existing Manufacturer. This is the column I am trying to create FK on.
My car.rb has 'belongs_to :manufacturer', and my manufacturer.rb has 'has_many :cars' to establish a one manufacturer to many cars relationship. However, when I create a new car (via scaffolding) the manufacturer_id field is blank.
I went to my cars_controller, found the 'create' method that is being used, and tried to add the second line below:
#car = Car.new(params[:car])
#car.manufacturer_id = car.manufacturer.id # <===
This produces a 'NameError in CarsController#create' error, and I see:
undefined local variable or method 'car' for #<CarsController:0x1034642f0>
Rails doesn't seem to like the line I've added. What am I missing to make this work?
Well, you need to have a manufacturer available before you can attach it to the car.
#car = Car.new( params[:car] )
m = Manufacturer.first # => as you can see you must already have one made
#car.manufacturer = m
#car.save
The reason car is undefined is because, well, you haven't defined it. Which car's manufacturer did you want to assign to #car?
So basically you need to make a manufacturer before you make a car. If the form you're filling out has the data for the manufacturer then make sure to put that under a different key in params, like, say, params[:manufacturer] and do a similar thing as you're doing with the car. Maybe like:
#car = Car.new( params[:car] )
#manufacturer = Manufacturer.find_or_create_by_name_and_country( params[:manufacturer][:name], params[:manufacturer][:country] )
#car.manufacturer = #manufacturer
#car.save
In your view, you want to generate a drop-down list for manufacturers (I would assume), so you should do something like this in the form:
<%= collection_select(:car, :manufacturer_id, Manufacturer.all, :id, :name) %>
Then your create action shouldn't need to explicitly set a manufacturer_id because it should have received that from the form.

Resources