This is an excerpt from a view -
<%= #user.id %> is the user id
<%= #book.id %> is the book id
<div class="field">
<%= f.select :contribtype, options_for_select(Contribution::CONTRIB_TYPES) %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I have passed the parameters for the user and the book from previous views, such that I have
http://localhost:3000/contributions/new?book_id=1&user_id=5
as the URL for the form. The correct user_id and book_id are showing up on the page.
I have the following in the controller -
def new
#user = User.find_by_id(params[:user_id])
#book = Book.find_by_id(params[:book_id])
#contribution = Contribution.new(params[book_id: #book.id, user_id: #user.id])
end
def create
#contribution = Contribution.new(contribution_params)
....
... but the user_id and book_id are not being captured in the object when it is created. I don't get any error, the data is simply not being set in the new object. Should I by passing parameters in the create action differently?
I'd use hidden fields as a quick fix:
#contribution = Contribution.new
in html:
<%= f.hidden_field :user_id, value: #user.id %>
<%= f.hidden_field :book_id, value: #book.id %>
be sure to permit those fields in your contribution_params
Related
I got this error with my user registration form in Rails:
ActionView::Template::Error (First argument in form cannot contain nil or be empty)
View:
<%= form_for User.new, url: create_user_path, method: :post do |f| %>
<div class="form-group">
<%= f.label :name, t("settings.account.fullname"), class: "form-label" %>
<%= f.text_field :name, class: "form-control #{form_is_invalid?(User.new, :name)}", placeholder: t("settings.account.fullname"), autofocus: "", required: "" %>
<div class="invalid-feedback d-block"><%=User.new.errors.full_messages_for(:name).first %></div>
</div>
Controller:
def create
#user = User.new(user_params)
#user.provider = #user_domain
end
and so on..
I'm new to ROR. Can any one help me with this please?
Apart from the bizarre error message this is just not how you do forms in Rails.
Since you're passing User.new to the form it will always be bound to a new instance of User. That means that anything the user has entered into the form will blanked out on an invalid form submission. User.new.errors.full_messages_for(:name).first will give a nil error since there are no validation messages on a record that has not been validated.
What you actually want is something like:
# routes.rb
resources :users
class UsersController < ApplicationController
# GET /users/new
def new
#user = User.new
end
# POST /users
def create
#user = User.new(user_params)
#user.provider = #user_domain
# ...
end
# ...
end
<%= form_with(model: #user) do |form| %>
<div class="form-group">
<%= f.label :name, t("settings.account.fullname"), class: "form-label" %>
<%= f.text_field :name, class: "form-control #{form_is_invalid?(User.new, :name)}", placeholder: t("settings.account.fullname"), autofocus: "", required: "" %>
<% if #user.errors.has_key?(:name) %>
<div class="invalid-feedback d-block">
<%= #user.errors.full_messages_for(:name).each do |msg| %>
<p><%= msg %></p>
<% end %>
</div>
<% end %>
<% end %>
If you just follow the Rails conventions you do not need to specify the URL or the method which are derived from the record. This lets you reuse the same form for updating existing records without changing anything in your code.
create_user_path is in itself extremely unidiomatic as Rails doesn't have a separate path for creating records. You create records by sending a POST request to the collection path (/users).
I've been writing a new RoR app for practice. This is a basic app that is supposed to function as a lookup page for animals.
I've been working on the Create/New functions in the controller for my page. I would like to make it so that a user can enter in an animal, and have the animal save to the SQL database. Afterwards, the page should redirect to the newly created animal page.
Here's my animals_controller.rb:
class AnimalsController < ApplicationController
def index
#animals = Animal.all
end
def show
#animal = Animal.find(params[:id])
end
def new
end
def create
# render plain: params[:animal].inspect
#animal = Animal.new(animal_params)
#animal.save
redirect_to #animal
end
private def animal_params
params.require(:animal).permit(:name, :scientific_name, :range)
end
end
Here is my views/animals/new.html.erb:
<h1> Add Animal </h1>
<%= form_for :animal, url: animals_path do |f| %>
<p>
<%= f.label :name %> <br>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :scientific_name %> <br>
<%= f.text_field :scientific_name %>
</p>
<p>
<%= f.label :range %> <br>
<%= f.select :range, ['land', 'sea', 'sky', 'underground'], :prompt => 'Select One' %>
</p>
<p>
<%= f.submit %>
<p>
<% end %>
When I try to enter in a new animal, here is what I get:
<ActionController::Parameters {"name"=>"cat", "scientific_name"=>"Felis catus", "range"=>"land"} permitted: false>
I'm wondering why I keep getting "permitted:false" when I have code in animals_controller.rb that states that these params are permitted! Can anyone point out anything or give me some suggestions?
Your params should look like
<ActionController::Parameters {"animal" => {"name"=>"cat", "scientific_name"=>"Felis catus", "range"=>"land"} } permitted: false>
Also, in the form, can you change :animal to #animal.
Alternatively, you can try this
params.require(:animal).permit(:name, :scientific_name, :range).permitted?
Problem is with this line render plain: params[:animal].inspect
because you are printing/accessing params directly without permission instead use :animal_params
render plain: animal_params.inspect
this lines #animal = Animal.new(animal_params) is fine. I guess your creating process works perfectly only.
I am having trouble passing a non-model form field from view to controller. The value I am trying to pass is amount
Thank you.
views/donations/index.html.erb
<%= form_tag donations_path, style: (current_user.card_last4? ? "display:none" : nil) do %>
<div id="error_explanation">
<% if flash[:error].present? %>
<p><%= flash[:error] %></p>
<% end %>
</div>
<article>
<%= label_tag(:amount, 'Donation Amount:') %>
<%= text_field_tag(:amount) %>
</article>
<%= link_to 'Donate', new_donation_path(amount: :amount), class: 'btn btn-primary', id: 'donateButton' %>
<% end %>
controllers/donations_controller.erb
def create
customer = current_user.stripe_customer
amount = params[:amount]
token = params[:stripeToken]
begin
Charge.charge(amount, token)
end
...
models/charge.rb
def self.charge(amount, token)
charge = Stripe::Charge.create(
amount: amount,
source: token,
currency: 'usd',
description: 'Test Charge'
)
end
...
Use a view tag like
<%= text_field_tag 'donation[amount]' %>
And permit the parameter in your controller
def donation_params
params.require(:donation).permit(:amount)
You can access the value with donation_params[:amount].
You shouldn't use link_to to trigger the form submission. Use submit_tag instead. Besides that, make sure your strong params whitelist whatever you're submitting.
I guess you are not using strong params. Why not just add |f| at the end like this
<%= form_tag donations_path, style: (current_user.card_last4? ? "display:none" : nil) do |f| %>
and then use <%= f.text_field :amount %>
Then at the params you should do something like params["donation"]["amount"] to get the value
EDIT: at the end change link_to for f.submit
I have a form in my rails app that accepts nested attributes. However, what I want to do is for rails to reject the creation of the nested model if a checkbox (outside the model itself) is checked.
Any idea on how to pass an attribute to the :reject_if option of the accepts_nested_attributes_for in the model from the controller?
Thank you very much in advance.
EDIT:
My controller looks like this:
def new
#course = Course.new
#course.course_template = CourseTemplate.new
end
def create
#course = Course.new(course_params)
#course.user = current_user
if #course.save
flash[:success] = t(".new_course_created_succefully")
redirect_to courses_path
else
render 'new'
end
end
And the form:
<%= form_for #course do |f| %>
<%= render 'shared/error_messages', error_model: #course %>
<div class="form-group has-feedback mb">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group has-feedback mb">
<div class="checkbox c-checkbox needsclick">
<label class="needsclick">
<%= check_box_tag "template", "1", false, {class: "needsclick"} %>
<span class="fa fa-check"></span>Is Template?
</label>
</div>
</div>
<%= f.fields_for :course_template do |ff| %>
<div class="form-group has-feedback mb">
<%= ff.label :name %>
<%= ff.text_field :name %>
</div>
<% end %>
<% end %>
send that checkbox as a parameter from the form and put the build operation inside an if statement. No need to bother with the reject_if
You need to handle your create and build operations separately. so instead of passing your model all attributes, youll pass the model the model attributes, and the association, the nested attributes
# controller
course = Course.new(course_params.reject{|attrib| attrib == :course_template_attributes})
unless params[:skip_create]
course.course_templates.build(course_params[:course_template_attributes]
end
...
what you need to do is conditionally create the course_templates, so you can just pass Course.new all your course_params because that creates both the course and the templates, which needs to be done separately.
Note I'm shorthanding with that reject statement up there. you can either manually add in the various params or better yet create another method with strong params and whitelist only the model attributes (not including the course_template_attributes)
additionally. the params[:skip_create] is whatever the parameter is for that checkbox that decides whether or not you want to create the templates
I'm playing with the messenger gem in rails 4.
I have a graph of nodes and I want to be able to bring up a message box (initially in a different page but will make it a partial later) when a node is pressed so that the current user can message that node.
The id for the clicked node is kept in a div called NameID
At the moment all I've got working is a button that opens the new message page and then you can choose a user from a drop down list. I guess I want that drop down list- the recipient- to be prepopulated from the currently clicked node on the index page.
Here is what I have so far:
index.html.erb
<p><a class="btn btn-lg btn-primary" id="BtnMessageNode" href="/messages/new">Start conversation</a></p>
<div id=NameID><<THIS IS POPULATED BY JAVASCRIPT>></div>
messages_controller.rb
class MessagesController < ApplicationController
before_action :authenticate_user!
def new
#chosen_recipient = User.find_by(id: params[:to].to_i) if params[:to]
end
def create
recipients = User.where(id: params['recipients'])
conversation = current_user.send_message(recipients, params[:message][:body], params[:message][:subject]).conversation
flash[:success] = "Message has been sent!"
redirect_to conversation_path(conversation)
end
end
helpers/messages_helper.rb
module MessagesHelper
def recipients_options(chosen_recipient = nil)
s = ''
User.all.each do |user|
s << "<option value='#{user.id}' data-img-src='#{gravatar_image_url(user.email, size: 50)}' #{'selected' if user == chosen_recipient}>#{user.name}</option>"
end
s.html_safe
end
end
messages/new.html.erb
<% page_header "Start Conversation" %>
<%= form_tag messages_path, method: :post do %>
<div class="form-group">
<%= label_tag 'message[subject]', 'Subject' %>
<%= text_field_tag 'message[subject]', nil, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'message[body]', 'Message' %>
<%= text_area_tag 'message[body]', nil, cols: 3, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'recipients', 'Choose recipients' %>
<%= select_tag 'recipients', recipients_options(#chosen_recipient), multiple: true, class: 'form-control chosen-it' %>
</div>
<%= submit_tag 'Send', class: 'btn btn-primary' %>
<% end %>
There are basically two ways to pass parameters to GET routes:
A. Named segments
/users/:user_id/message/new
This nested route would be great if you are sending a message to a single user.
B. Query parameters
Rails supports query parameters as well:
/message/new?to=2
Rails automatically adds query parameters to the params hash. So in this case you would do params[:to].
You can use the Rails route helpers so that you don't have to deal with encoding urls yourself:
new_message_path(to: #user.id)
Use query params for optional parameters like filters and sorting or in this case a preset. Don't use them like users?id=5.