How to add new object of model in a foreign controller - ruby-on-rails

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

Related

Check if a table value in one model matches a table value in a different model

This question is kind of hard to ask, but basically, I have a Class model and a User model, each Class table has a token, and so does each User one. After the user submits a sign up form, how would I set the value of the users class_id in the create action? I've tried <%= f.hidden_field :app_id, :value => App.find_by_token(params[:key]) %>, but this doesn't work. Sorry for the long and confusing question, will be glad to answer more. Thanks in advance for any answers
It sounds as though you have a "relationship" where a User belongs to a Class and a Class could have many users. If that is the case then you should use rails Associations to make it easy for yourself. This would involve adding a 'has_many :users' to your Class model and a 'belongs_to :class' call to your User model. You would then just use the rails helpers to 'build' the object and save it with the association in the corresponding controllers.
The manual way to do it would be as follows from your controller:
def create
#This would involve you sending the proper class id as a hidden form field with the form field attribute named 'class_id'. You may need to add 'attr_accessor :class_id' to your User model.
if user.create(user_params)
blahblahblah
else
sorry blah blah
end
end
private
def user_params
params.require(:user).permit(:name, :email, :class_id, :etc)
end

How to correctly pass through foreign keys in Rails form_for

I currently have a working form to create a resource (An event booking) which belongs_to two other models, a Consumer (the customer) and a Course. In the Booking creation form, I'm using two hidden fields which pass through consumer_id and course_id.
For this to work in form_for, I've created two virtual attributes in my Booking model
attr_accessor :course_id, :consumer_id
And in the create event of BookingsController, I've grabbed those ID's from mass assignment and then manually assigned the actual Course and Consumer objects from the ID
bookings_controller.rb
def create
#booking = Booking.new(booking_params)
#booking.course = Course.find(#booking.course_id)
#booking.consumer = Consumer.find(#booking.consumer_id)
if #booking.save_with_payment
# Payment was successful, redirect to users account page to view it and past bookings
else
render :new
end
end
private
def booking_params
params.require(:booking).permit(:course_id, :consumer_id, :card_token, :visible, :created_at)
end
Is this best practice? I tried to name the form hidden fields as consumer and course, hoping that Rails would see that the value is an ID and automatically do a .find for me, but that doesn't appear to be the case. I'll be surprised if Rails can't take care of this automatically, I'm just not sure how to accomplish it.
It's simpler than you imagine and you're already most of the way there.
When you create a booking, you need only to set the course_id and consumer_id fields, so make sure you've got hidden fields set up in your form with these names and the right values:
<%= f.hidden_field :course_id, value: my_course_id %>
<%= f.hidden_field :consumer_id, value: my_consumer_id %>
Don't set course or consumer in your controller or in your form. That is, remove the following lines from your controller:
#booking.course = Course.find(#booking.course_id)
#booking.consumer = Consumer.find(#booking.consumer_id)
You already have course_id and consumer_id in your permit list, so when you post the form, the values for those parameters will be set on your new booking, which is all that you should care about.
When you attempt to access #booking.course, ActiveRecord will do a find for you based on the id set in course_id; this is handled by the belongs_to association that you've established in your model.

Attaching default params with a form

In order for a user to use my search form, they type a user's name, press submit, then rails brings up that user's homepage. I am still a beginner, and the "homepage" the user arrives is a response to the GET method pointed at the URL http://localhost:3000/center/show_user?utf8=%E2%9C%93&name=test&commit=Search when I type the user name "test" in the search box.
In the controller action center#show_user, I have set #user = User.find_by(name: params[:name])
and in the view, it displays well with <%= #user.name %>.
I would like to make a form on the center#show_user page for creating a new "item". An item is defined at belonging to the user in the scheme and a user is defined as owning many items (a user has an item_id column and an item has a user_id column).
When this form is submitted, how do I include with it the current user_id, inherited from the params in the url on the page hosting the form? For example, if I go to the page of the user named "sample_user", I want to be able to submit a "new item" form and have the user_id automatically included along with that form.
'Central' controller code for this page is
def show_user
#user = User.find_by(name: params[:name])
end
Just add
<%= hidden_field_tag "user_id", current_user.id %>
to form.
You should create the "item" through the relation with the user. That means:
Given this in your user model:
class User < ActiveRecord::Base
has_many :items
end
Do the following in the controller:
def create
#user = User.find_by(name: params[:name])
#user.items.create(params[:item])
# redirect_to or something different...
end
This will automatically build the relation for you (basically filling in the user_id field for you). The reason for doing it this way is that users can't mess with your form and fill in other user ids in the hidden field.

Model Relationships

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

nested form & habtm

I am trying to save to a join table in a habtm relationship, but I am having problems.
From my view, I pass in a group id with:
<%= link_to "Create New User", new_user_url(:group => 1) %>
# User model (user.rb)
class User < ActiveRecord::Base
has_and_belongs_to_many :user_groups
accepts_nested_attributes_for :user_groups
end
# UserGroups model (user_groups.rb)
class UserGroup < ActiveRecord::Base
has_and_belongs_to_many :users
end
# users_controller.rb
def new
#user = User.new(:user_group_ids => params[:group])
end
in the new user view, i have access to the User.user_groups object, however when i submit the form, not only does it not save into my join table (user_groups_users), but the object is no longer there. all the other objects & attributes of my User object are persistent except for the user group.
i just started learning rails, so maybe i am missing something conceptually here, but i have been really struggling with this.
Instead of using accepts_nested_attributes_for, have you considered just adding the user to the group in your controller? That way you don't need to pass user_group_id back and forth.
In users_controller.rb:
def create
#user = User.new params[:user]
#user.user_groups << UserGroup.find(group_id_you_wanted)
end
This way you'll also stop people from doctoring the form and adding themselves to whichever group they wanted.
What does your create method look like in users_controller.rb?
If you're using the fields_for construct in your view, for example:
<% user_form.fields_for :user_groups do |user_groups_form| %>
You should be able to just pass the params[:user] (or whatever it is) to User.new() and it will handle the nested attributes.
Expanding on #jimworm 's answer:
groups_hash = params[:user].delete(:groups_attributes)
group_ids = groups_hash.values.select{|h|h["_destroy"]=="false"}.collect{|h|h["group_id"]}
That way, you've yanked the hash out of the params hash and collected the ids only. Now you can save the user separately, like:
#user.update_attributes(params[:user])
and add/remove his group ids separately in one line:
# The next line will add or remove items associated with those IDs as needed
# (part of the habtm parcel)
#user.group_ids = group_ids

Resources