Attaching default params with a form - ruby-on-rails

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.

Related

rails store current user email in database on form submit

I have a column in my database called 'email'. I want to store the current logged in user's email address into this column when they submit a specific form.
At first I thought I should write something in the html to grab the current user's email address and hide it in the form somewhere but I realized that was probably a bad idea since anyone would be able to modify the html to put any email address that they want in there.
So my question is, would I go about this in the controller? If so, how would I go about doing that?
I'm naming that other model as Article(you can use yours)
Have a column called user_id instead of email in that table
Class User
has_many :articles
end
Class Article
belongs_to :user
end
class ArticlesController
def create
#article = current_user.articles.new(article_params)
#article.save
end
def article_params
params.require(:article).permit(:field1, :field2)
end
end
If you do something like this then automatically user_id will be saved in that table.
So it will be easy for you to get all articles which is belonged to that user.
user = User.first
user.artciles # you will get all articles belonged to that user
article = Article.first
article.user # you will get user of that article
Hope this helps
Figured it out
#request.email = current_user.email
#request.save

Rails 5 - Best way to hold onto params for creating associations?

Here's the scenario to illustrate my question. I have 2 models:
# models/post.rb
belongs_to :user
validates_presence_of :comment
And we have a devise model called Users
# models/user.rb
has_many :posts
What I would like to achieve:
Person comes to the website, is able to create a Post, after creating the Post, they are prompted to create an account. After creating the account, the Post that they just created would be associated to the User they just created.
Usually i'd make use of routes to hold the params[:id] which can be accessed in the controller method. For example the URL may look something like this:
www.foo.com/foo/new/1
And then I can do this:
# foo_controller.rb
def new
#foo = Foo.new
#parent = Parent.find(params[:id])
end
And in the view I can simply access #parent and use a hidden field to fill the parent ID.
But when routing through so many different pages (such as creating a Devise User), how do I hold onto the parent/child ID such that I can still create that association?
Using an hidden field or the route to store the id, with no authorization in the process, would not be secure. What if I just use the browser inspector and change the value of the id ? Your cool post would be mine.
What you could do is, for instance, add a field called guest_id to the Post, in which the value is unique (like SecureRandom.uuid), and also store that value in the session.
Thus, after the user is created, you could do something like that
if (post = Post.find_by(guest_id: session[:guest_id])).present?
post.update(user_id: current_user.id)
end

Member action for custom actions on one field

I have a User table with common fields: name, age, gender etc... In my application, when a new user signs up I want to check (approve or reject) his bio and profile photo to validate his account. I'm using ActiveAdmin and I wanted to have something like a scope in my User index where I see the "unchecked" user (I have done that part) and an action link(next to View, Edit and Delete) to approve or reject the bio/photo.
My problem is with this action link, I don't know how to do it. I've seen member_actions for custom actions, but I don't understand how it works and if I can modify one field one my user. Some help would be welcome on this.
ActiveAdmin lets you specify a custom action like approve
ActiveAdmin.register User do
member_action :approve, method: :put do
resource.approve!
redirect_to resource_path, notice: "Approved!"
end
end
Create a method in your Model to do what's necessary to approve, for example if approved is a boolean in your table, then
class User < ActiveRecord::Base
def approve!
update(approved: true)
end
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.

How to redirect from one action of controller A to an action of controller B and back in Rails?

I have two associated models, Employee and Company:
class Employee < ActiveRecord::Base
attr_accessible :name
belongs_to :company
attr_accessible :company_id
end
class Company < ActiveRecord::Base
attr_accessible :name, :industry, :owner
has_many :employees
end
What I want to implement is that when, in the new employee form, the user types a company name that doesn't exist he/she should be redirected to the new company form, with the name field already filled with the value of the previous form, fill it in for the company to be created and then get redirected to the "employee successfully created" page (but if and only if the company is created first).
I have managed to create a company at the same time the employee is created, with the below code:
def create
#employee = Employee.new(params[:employee])
#company = Customer.find_or_create_by_name(params[:company][:name])
#company.employees << #employee
#company.save
#employee.save
end
However, this doesn't give me the option to fill in the rest of the company information.
Experimenting with redirect_to, I have also managed to send the user to the edit company form.
# one way to tell if the company has all its attributes filled
if #company.industry.blank?
redirect_to edit_company_path(#company), notice: "Please edit the company details" and return
end
*the and return statement is necessary as otherwise I get a "The redirect_to was called multiple times" error*
However, this is not the desired behaviour - for two reasons:
The employee is created even when the company is not.
The user is not informed about the employee creation.
So, my thinking is that I am redirecting to the company controller and the create action the right way and that I should somehow redirect back to where I was (right before the #employee.save) in the employee controller. But how? Also, is that the best and "most-rails" way to do it?
One option I see is to save employee data in session (session[:temp_employee] = params[:employee]), then redirect to creating the company. In the company controller, after the company is saved you could check if employee is present in the session then redirect client back to create action of the employees controller.
This would additionally require you to:
Enable access to create action via path (like: get 'create', to: 'employees#create')
In the employees create action take for attributes from session variable if it is present, otherwise fallback to the params hash.

Resources