Rails - Passing a variable while using Simple Form - ruby-on-rails

When creating a new model object using simple form, I need to pass the id of one object to the new object as it relies on the id for its URL. The routing is:
resources :coins do
resources :questions
end
I am attempting to do this using a hidden field tag but its not working. The ID is not passed and as a result, the new object does not save.
<%= simple_form_for #question, url: coin_questions_path(#coin.id) do |f| %>
<%= f.input :ques_num %>
<%= f.input :content %>
<%= hidden_field_tag(:coin_id, #coin.id) %>
<%= f.button :submit, 'Submit' %>
<% end %>
Prior to this, I was using collection_select in simple form to manually enter the ID and it worked, however I need it to happen automatically. Is there a better way of doing this that will do what I am looking for?
Question model:
class QuestionsController < ApplicationController
before_action :find_question, only: [:show, :edit, :update, :destroy ]
before_action :find_coin
before_action :authenticate_user!, except: [:index, :show]
def index
#questions = Question.where(coin_id: #coin.id).order("created_at DESC")
end
def show
end
def new
#coin
#question = current_user.questions.build
end
def create
#question = current_user.questions.build(question_params)
if #question.save
redirect_to coin_question_path(#coin.id, #question.id)
else
render 'new'
end
end
.
.
.
private
def find_question
#question = Question.find(params[:id])
end
def find_coin
#coin = Coin.find(params[:coin_id])
end
def question_params
params.require(:question).permit(:content, :ques_num, :coin_id)
end
end

You could easily use hidden_field with a value - read more
For example:
<%= f.hidden_field :coin_id, value: #coin.id %>
And then the value will be in the params[:question][:coin_id] on create, so the rest should work as it is now. :)

<%= hidden_field_tag(:coin_id, #coin.id) %> will generate a field with a name of just "coin_id"; you want "question[coin_id]"
You should, in turn, assign this value to the object in your controller. #question.coin_id = #coin.id, or #question = Question.new(:user => current_user, :coin => #coin) or #question = current_user.questions.new(:coin => #coin)
<%= f.input :coin_id, :as => :hidden %>

Related

How can I create a form without using resources (action :new, :create) in Rails?

This is my controller
class SchoolsController < ApplicationController
def teacher
#teacher = Teacher.new
end
def form_create
#teacher = Teacher.new(teacher_params)
if teacher.save
redirect_to schools_teacher_path
else
flash[:notice] = "error"
end
end
private
def teacher_params
params.require(:teacher).permit(:name)
end
end
This is my views/schools/teacher.html.erb
<%= form_for :teacher do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
I am new to Ruby on Rails, and not sure how to proceed.
You should move this to a TeachersController let me show you how:
First you need to create the controller, you can get this done by typing this on the terminal at the project root directory:
$ rails g controller teachers new
Then into your route file (config/routes.rb):
resources :teachers, only: [:new, :create]
After that go to the teachers_controller.rb file and add the following:
class TeachersController < ApplicationController
def new
#teacher = Teacher.new
end
def reate
#teacher = Teacher.new(teacher_params)
if #teacher.save
redirect_to schools_teacher_path
else
redirect_to schools_teacher_path, notice: "error"
end
end
private
def teacher_params
params.require(:teacher).permit(:name)
end
end
Then you can have the form at views/teachers/new.html.erb:
<%= form_for :teacher do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
Please let me know how it goes!

options_for_select on simple_form

I'm probably using this incorrectly and I cant figure it out.
I am using an options_for_select on my simple_form. It renders fine with no errors, but the selected option does not save to the database. All other fields save no problems.
The select_tag is
<%= select_tag :experiment_type, options_for_select(['AOV', 'Conversion']), :prompt => "Select a Project Type" %>
Controller:
class ExperimentsController < ApplicationController
before_action :find_advertiser
before_action :find_experiment, only: [:edit, :update, :show, :destroy]
def index
#experiments = Experiment.all.order("created_at DESC")
end
def show
end
def new
#experiment = Experiment.new
#advertisers = Advertiser.all.map{ |c| [c.name, c.id] }
end
def create
#experiment = Experiment.new(experiment_params)
#experiment.advertiser_id = params[:advertiser_id]
if #experiment.save
redirect_to advertiser_path(#advertiser)
else
render 'new'
end
end
def edit
#projects = Project.all.map{ |c| [c.name, c.id] }
end
def update
#experiment.advertiser_id = params[:id]
if #experiment.update(experiment_params)
redirect_to experiment_path(#experiment)
else
render 'edit'
end
end
def destroy
#experiment.destroy
redirect_to root_path
end
private
def experiment_params
params.require(:experiment).permit(:advertiser_id, :name, :experiment_type, :hypothesis, :priority, :status, :launch_date,
:description, :baseline_url, :test_url, :baseline_aov_60, :baseline_aov_30, :baseline_aov_mtd,
:baseline_conversion_60, :baseline_conversion_30, :baseline_conversion_mtd)
end
def find_advertiser
#advertiser = Advertiser.find(params[:advertiser_id])
end
def find_experiment
#experiment = Experiment.find(params[:id])
end
end
I would need your full form layout to tell you for sure, but according to your experiment_params method, experiment_type field is a part of experiment. However, when you use just select_tag it is not connected to your main object. You need to use just select. Similar to this:
<%= simple_form_for :experiment do |f| %>
...
<%= f.select ... %>
...
<% end %>
or in the simple_form format:
<%= f.input :experiment_type, collection: ['AOV', 'Conversion'] %>
My guess is also based on your hash:
"experiment_type"=>"AOV", "experiment"=>{"name"=>"Test" ....
The experiment_type is outside of your "experiment".

Trying to have 2 forms pass to 2 different controllers from one view

I have 2 forms in one view one is displayed if the user is a moderator and the other if it is a normal user and they both send the information to 2 different controllers. My problem is that if its a normal user, the form that is displayed for them uses the wrong controller.
Here is the coding
categories/new.html.erb
<% if current_user.mod_of_game? #guide %>
<%= form_for([#guide, #category], url: guide_categories_path) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name, "Category name" %>
<%= f.text_field :name %>
<%= f.submit "Next" %>
<% end %>
<% else %>
<%= form_for([#guide, #check_category], url: check_category_post_path) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name, "Category name" %>
<%= f.text_field :name %>
<%= f.submit "Next" %>
<% end %>
<% end %>
Categories controller
before_action :mod_checker, only: [:create]
def new
#guide = Guide.friendly.find(params[:guide_id])
#category = Guide.friendly.find(#guide.id).categories.new
#check_category = CheckCategory.new
end
def create
#guide = Guide.friendly.find(params[:guide_id])
#category = Guide.friendly.find(#guide.id).categories.new(category_params)
if ((#category.save) && (current_user.mod_of_game? #guide))
flash[:info] = "guide category added succesfully!"
redirect_to #guide
else
render 'new'
end
end
private
def category_params
params.require(:category).permit(:name)
end
def mod_checker
#guide = Guide.friendly.find(params[:guide_id])
unless current_user.mod_of_game? #guide
flash[:danger] = "Sorry something went wrong!"
redirect_to root_path
end
end
check_categories controller
def new
end
def create
if #check_category.save
flash[:info] = "Game category added successfully. A mod will apporve it shortly."
redirect_to #guide
else
render 'new'
end
end
private
def check_category_params
params.require(:check_category).permit(:name)
end
and the routes
resources :guides do
resources :categories, only: [:new, :create, :edit, :update]
end
resources :check_categories, only: [:new, :edit, :update]
match 'guides/:guide_id/categories/' => 'check_categories#create', :via => :post, as: :check_category_post
sorry the coding is a bit messy, the 4 spaces to put it in a code block was spacing my coding weird.
When i have a non moderator user submit the form, the before action in the categories controller is run and I'm redirected to the homepage. I don't know why it does this because the submit path should go to the check_categories controller for non moderator users, the check_categories controller doesn't have the before filter.
Why does it use the before filter in the controller I'm not using for that form? How can I fix it?
Building this app to learn rails better. So I can only assume lack of rails knowledge is causing me to do something wrong.
Bad practice to have two forms with identical code (apart from the path) - goes against DRY Don't Repeat Yourself.
As mentioned by #Akash, this sounds like a job for authorization.
Further, it also denotes that you have issues with the underlying structure of your code. Specifically, you have an antipattern with CheckCategory (you can put it all into the Category model):
#config/routes.rb
resources :guides do
resources :categories, only: [:new, :create, :edit, :update] do
patch :approve, on: :member
end
end
#app/models/category.rb
class Category < ActiveRecord::Base
before_action :set_guide
def new
#category = current_user.categories.new
flash[:notice] = "Since you are not a moderator, this will have to be approved." unless current_user.mod_of_game? #guide
end
def create
#category = current_user.categories.new category_params
#category.guide = #guide
#category.save
end
def approve
#category = #guide.categories.find params[:id]
#category.approve
end
private
def set_guide
#guide = Guide.find params[:guide_id]
end
end
#app/views/categories/new.html.erb
<%= form_for [#guide, #category] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :name, "Category name" %>
<%= f.text_field :name %>
<%= f.submit "Next" %>
<% end %>
The above will solve most of your structural issues.
--
To fix the authorization issue, you'll be best denoting whether the category is "approved" in the model:
#app/models/category.rb
class Category < ActiveRecord::Base
enum status: [:pending, :approved]
belongs_to :user
belongs_to :guide
validates :user, :guide presence: true
before_create :set_status
def approve
self.update status: "approved"
end
private
def set_status
self[:status] = "approved" if self.user.mod_of_game? self.guide
end
end
--
If I understand correctly, you want to allow anyone to create a category, but none-mods are to have their categories "checked" by a moderator.
The code above should implement this for you.
You will need to add a gem such as CanCan CanCanCan to implement some authorization:
#app/views/categories/index.html.erb
<% #categories.each do |category| %>
<%= link_to "Approve", guide_category_approve_path(#guide, category) if category.waiting? && can? :update, Category %>
<% end %>
Use "Cancan" Gem and give authorization

Form_for data not accessible in custom action

I have a form_for #user to update a column in user model .
I have given html method as get and submitting to action look like
#user = User.find(params[:id])
#user_update_attribute(:phno,params[:phno])
and in view its look like
<%= form_for :#user, url: addphno_addphno_path , html: { method: :get } %>
The issue is I am not able to get data in controller action.the error is
could not find record of "id="
If you wanted to have a separate "phoneno" action:
#config/routes.rb
resources :users do
match :addphone, via: [:get, :post]
end
#app/views/users/add_phone_no.html.erb
<%= form_for #user, user_addphone_path(#user) do |f| %>
<%= f.text_field :number %>
<%= f.submit %>
<% end %>
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def addphone
#user = User.find params[:id]
#user.update( update_params ) if request.post?
end
private
def update_params
params.require(:user).permit(:phno)
end
end
If you wanted to use the update action (as is convention):
#config/routes.rb
resources :users
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def edit
#user = User.find params[:id]
end
def update
#user = User.find params[:id]
#user.update user_params
end
private
def user_params
params.require(:user).permit(:phno)
end
end
This will allow you to call:
#app/views/users/edit.html.erb
<%= form_for #user do |f| %>
<%= f.text_field :phno %>
<%= f.submit %>
<% end %>
Bottom line is that you should be using the second batch of code if you're updating your #user object.
I originally thought you wanted to add a phone number as associative data to your #user... but it seems that you just wish to add a phone number for the user. To do this, the above code will suffice.

param is missing or the value is empty error

I am having trouble with the params.require().permit(). I have a User model from devise and a group model which represents a class (as in an academic class). When the user is on the groups index view I want them to be able to click join and become part of that group.
<%= form_for #student, :url => students_path(#student), method: :post do %>
<%= hidden_field :student_id, :value => current_user.id %>
<%= hidden_field :course_id, :value => group.id %>
<%= submit_tag "+ Join", :class => "btn btn-primary pull-right join-button" %>
<% end %>
My thinking was I would pass the current users id as well as the group ID that they click join for as hidden values so there would just be a join button.
My group controllers index method looks like this
def index
#groups = Group.all
#student = Student.new
end
My Student Controller looks like this:
class StudentsController < ApplicationController
before_action :set_student, only: [:show, :edit, :update, :destroy]
def index
##students = Student.all
#students = Student.where(:student_id => current_user.id)
#respond_with(#students)
end
def show
#respond_with(#student)
#students = Student.find(params[:id])
end
def new
#student = Student.new
#respond_with(#student)
end
def edit
end
def create
#student = Student.new(student_params)
#student.save
#respond_with(#student)
end
def update
#student.update(student_params)
#respond_with(#student)
end
def destroy
#student.destroy
#respond_with(#student)
end
private
def set_student
#student = Student.find(params[:id])
end
def student_params
params.require(:student).permit(:course_id, :student_id)
end
end
Whenever I try and submit the form (aka click the join button) I get an error saying:
param is missing or the value is empty: student
I also get this info which is correct as far as the student and group ID's
Request
Parameters:
{"authenticity_token"=>"/bJYZBGr6lfAzb9mYnvRfMZII+QS8iskd0MRuHh+RnE=",
"course_id"=>"10",
"student_id"=>"4"}
This also does insert into the database, but the student_id and course_id are nil. I am guessing this has something to do with strong params but I am not sure what I am doing wrong.
It looks like your form_builder object is missing from the form_for block. Try this:
<%= form_for #student, :url => students_path(#student), method: :post do |f| %>
<%= f.hidden_field :student_id, :value => current_user.id %>
<%= f.hidden_field :course_id, :value => group.id %>
<%= submit_tag "+ Join", :class => "btn btn-primary pull-right join-button" %>
<% end %>
without the builder I don't believe rails will provide a student hash in the submitted params
in the before _action set_student
you are usin param[:id] , while your params don't have it .. I think you should use param[:student_id] instead
Since you're passing #student isn't the path just student_path(#student) rather than what you had, which is students_path(#student)?

Resources