I have two models, User, and Product. Product belongs to User, User has many Products.
When a Product is created I also want to update multiple fields in the User model. I've been developing with Ruby for like 2 years now and still don't understand forms fully when it comes to this stuff. I'm still getting permitted: false. Now I know that for instance if I was creating a user while also creating a product I would just do #product.user.build but in this case I just want to update an already existing record.
I also realize that I probably can't call f.fields_for :user as #product doesn't know about user yet. In my head I believe I should be able to just pass additional params to the form, grab the current_user in the product#create action and then update the attributes manually by calling update_attributes on user.
product.rb
accepts_nested_attributes_for :user
product controller
def new
#product = Product.new
end
params.require(:product).permit(:product_name, user_attributes: [:phone_number, :email_address])
product view
form_for #product do |f|
f.fields_for :user do |c|
c.text_field :phone_number
c.text_field :email_address
f.text_field :product_name
end
I also realize that I probably can't call f.fields_for :user as #product doesn't know about user yet.
You can assign attributes to #product without saving it.
def new
#product = Product.new(
user: current_user
)
end
Now #product.user works.
Related
Should I manually add a user_id into the hidden form? Or is there a better way?
I have models:
class Project < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :projects
end
In my view:
<%= simple_form_for #project do |f| %>
<%= f.hidden_field :value => current_user.id %>
<% end %>
Or is there another way to do this? I thought if the model was associated with each other, it would automatically add the user_id into the database for projects?
Thanks!
Edit: Converted all trip to projects, so others needing help knows
Nope. That shouldn't be in form, because of everybody can change hidden value at the form.
Assuming you are using strong parameters
def create
#project = Project.new(project_params)
#project.save # or something else
end
def project_params
params.require(:project).permit(something_permitted_here)
.merge(user_id: current_user.id)
end
If you put user id on hidden form it will cause a breach in security. Because using browser tools a hacker can change the user_id and can inject information for other user. A better way is to put it into controller.
Inside controller, you can do so:
def create
#project.user = current_user
#project.save
#...
end
This way you protect yourself against someone manually changing the user_id in html.
Use the association to your advantage:
def create
#project = current_user.projects.build(project_params)
if #project.save
# ...etc
end
I have a User model, and two models that inherit from that: Teacher and Student. They also have their own controllers that inherit from the User controller.
I also have a Group model.
group belongs to teacher, teacher has many groups. group has and belongs to many students. student has and belongs to many groups.
There is a join table for the HABTM relationships, called 'groups_students'.
I have managed to create a form element that allows me to set the 'type' of User to 'Student' or 'Teacher'.
The difficulty I have now is assigning students to groups in the view. I can do this in the console no problem, as outlined here: Rails 4 HABTM how to set multiple ids in console?
I'm stumped as to how to do this in a view. I want to do it in the Student's show view.
Can someone at least give me some guidance? I have a pretty good book on Rails, but I need to know roughly what I have to do.
In the end I actually paid someone to solve this for me, because I couldn't find any free help for this on the internet. Thankfully, it wasn't too easy for him to solve, but solve it he did:
views/users/show.html.erb:
<%= form_tag assign_to_group_path do %>
<%= hidden_field_tag :user_id, #user.id %>
<%= select_tag :group_id, options_from_collection_for_select(Group.all, "id", "title") %>
<%= submit_tag "Assign to Class" %>
<% end %>
users_controller.rb:
private
def user_params
params[:user].permit(:type) if params[:user]
end
students_controller.rb (inherits from users_controller.rb):
def assign_to_group
#user = User.find(params[:user_id])
#group = Group.find(params[:group_id])
#user.groups << #group unless #user.groups.include? #group
#user.save!
redirect_to user_path #user
end
routes.rb:
post 'assign_to_group' => 'students#assign_to_group'
I have a comment model and when a comment is created it makes a note of the profile_name of the user and saves it. So it is basically saving #user.profile_name as comment.profile_name.
If I now want to show additional information from the user who has that profile_name such as #user.avatar - how would I query it without having to add extra fields to be saved when a comment is created?
I Imagined I could do something like
#user = User.all
#comment_user = User.where(:profile_name => #user.profile_name)
And then run
<% #comment_user.each do |user| %>
<%= user.first_name %>
<% end %>
In the view but I get an error
undefined method `profile_name' for #<ActiveRecord::Relation::ActiveRecord_Relation_User:0x007fc2081c7290>
I'm not even sure if that is the correct way to proceed even if I didn't get the error.
The error is because you are trying to call profile_name on User.all, but what you want is a single user. Try:
#user = User.first
#comment_user = User.where(:profile_name => #user.profile_name)
That being said, you should be using ActiveRecord associations instead. Instead of storing the user's profile_name in the comment record, you should store the user_id . Create a belongs_to :user association in the Comment model and then you can access the other user attributes directly.
First add a :user_id integer column to the the comments table, and then define your associations:
class Comment < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :comments
end
When creating a new comment, you can do something like:
#comment = #user.comments.create(text: 'my awesome comment')
Then in your view:
<%= #comment.text %>
<%= #comment.user.profile_name %>
I have a classified model that is hook up to the student model in a way that it looks like this
classified.rb
belongs_to :student
in my student model it
has_many :classifieds
The classifieds table contain a column for student_id
when I head to the rails console
I can create a new classified for that particular student record by doing
Student.find(19).classifieds.create(:ad_title => "blah", :ad_content => "blah", :location => "blah")
The record automatically gets a student_id generated because it was created in the student standpoint.
Now the problem is I have a classifieds controller with a new and a create method and a new form in the view
I am creating a new ad in the classifieds standpoint here is the form
<div>
新广告: <br><br>
<%= simple_form_for #advertisement do |f| %>
<%= f.input :ad_title, label: "Title" %><br>
<%= f.input :ad_content, label: "Content"%><br>
<%= f.input :location, label: "Location"%><br>
<%= f.input :student_id, label: "Your Student ID"%><br>
<%= f.button :submit, "Add an Advertisement" %>
<% end %>
</div>
The problem is the student_id must exist in order for that particular record to show up in index and my users don't know their id.
How do I create a classified in the student standpoint using forms
I consider going to my students controller and adding a method like this
def create_classified_ad
#student = Student.find(params[:id])
#classified = #student.classified.create(params[:classified])
end
I am using devise so there is user session? I don't know how sessions work entirely I want that particular student to be found after logged in and have that student create a classified ad with the inputs from the form so the record will be created correctly?
The question is more like how do you insert data using forms to a hooked up table correctly? (and not merely inserting data into a simple no relationship table)
You should not be passing the student_id from the form. If you have a devise session, you should have access to current_user:
def new
#classified = current_user.classifieds.build
end
def create
#classified = current_user.classifieds.build(params[:classified])
if #classified.save
# do something
else
# handle failure
end
end
In the index, you can do this:
def index
#classifieds = current_user.classifieds.all
end
All of this assumes you have a devise session. If not, just fetch the student like so:
#student = Student.find(params[:student_id])
#classified = #student.classifieds.build
Set up a nested route for the classifieds under the user:
resources :users do
resources :classifieds
end
This allows you to fetch the student from a student_id param. Your route would like this: new_student_classified_path(#student).
I'm building a nested model form that will allow a client to register (client model) and create a login (user model) at the same time. However, for new registrants, I would like to set the user.role_code (say to "A" for admin), but I've been struggling with this. From a data model perspective, and client has multiple users, since after registration, the client can access the app to add other users. From that perpective, I don't think I can default user_role in the model, since for added users, their role_code may be different. I would like to set the default in the controller.
Also, after form submission, users are sent as an array, so I would like to ensure only ONE user array object is sent upon registration (clearly for vulnerability reasons).
Here's my code
#client registration form new.html
<%= form_for #client do |client_form| %>
.....
<%= client_form.fields_for :users do |user_form| %>
<div class="field">
<%= user_form.label :first_name %>
<%= user_form.text_field :first_name %>
</div>
.....
#client Controller
def create
logger.info params.inspect
#client = Client.new(params[:client])
if #client.save
......
#client model
class Client < ActiveRecord::Base
attr_accessible :business_name, ... #and more
attr_accessible :users_attributes
has_many :users
has_many :items
accepts_nested_attributes_for :users, allow_destroy: true
#logger.info params.inspect
"...users_attributes"=>{"0"=>{"first_name"=>..."
Found it!!! After much researching, Googling, pulling out my hair, and lastly coming across Get nested params, the answer is as follows:
#client.users.first.role_code = "A"
and to test the number of user array objects, use the following
if #client.users.size != 1
...
end