Ruby on Rails new() method not storing values - ruby-on-rails

I have a modified copy of https://github.com/talho/openphin/blob/master/app/controllers/admin/invitations_controller.rb
The main code is primarily the same, however our system was upgraded a few months back to Rails 4.x and the invitation system no longer works.
The method with the issue is create. I have tried swapping out:
#invitation = Invitation.new(params[:invitation])
with
#invitation = Invitation.create(invitation_params)
And creating
def invitation_params
params.require(:invitation).permit!
end
However, here is what I have:
invitation_params = {"name":"Test","subject":"test","body":"test","organization_id":"","author_id":24448}
#invitation = {"id":null,"name":null,"body":null,"organization_id":null,"author_id":null,"subject":null,"created_at":null,"updated_at":null,"lock_version":0}
Also, if I use create!, then my output error is:
E, [2015-12-14T13:03:38.664099 #24385] ERROR -- : Validation failed: Author can't be blank (ActiveRecord::RecordInvalid)
I could use any guidance/help on why everything ends up as null.

You call return what leaved the method, before you call save! in the record. Furthermore you might want to read about Strong Parameters. You might want to change your code to:
#invitation = Invitation.new(
params.require(:invitation).permit(
:name, :subject, :body, :organization_id, :author_id
)
)
#invitation.save!
render :json => { :invitation => #invitation }.as_json
return
Please note that you usually do not need to call return in controller method. And when you call save! immediately after new then create! might be an better option:
def create
invitation = Invitation.create!(invitation_params)
render json: { invitation: invitation }.as_json
end
private
def invitation_params
params.require(:invitation).permit(
:name, :subject, :body, :organization_id, :author_id
)
end

Related

Rails multiple params permit calls

I am trying to use multiple permits in a single method similar to the following (psuedocode)
def index
model.create(
params.permit(:b, :c)
)
params.permit(:a)
end
This is my actual code
def create
params.permit(:create_special_categories)
balance_sheet = ::BalanceSheet.create!(
balance_sheet_params.merge(date: Time.zone.now.to_date, entity: #entity)
)
balance_sheet.create_special_categories if params[:create_special_categories]
render json: balance_sheet, serializer: ::Api::V3::BalanceSheetSerializer
end
def balance_sheet_params
params.permit(
:id,
:entity,
:entity_id,
:date,
:name
)
end
However, I get the following error...
ActionController::UnpermittedParameters:
found unpermitted parameter: :create_special_categories
UPDATE
my solution was to avoid strong parameters all together.
def create
balance_sheet = ::BalanceSheet.new(
date: Time.zone.now.to_date, entity: #entity
)
balance_sheet.name = params[:name]
balance_sheet.save!
balance_sheet.create_special_categories if params[:create_special_categories]
render json: balance_sheet, serializer: ::Api::V3::BalanceSheetSerializer
end
This line doesn't have any effect, params.permit are not chained or added to a previous permit, you must use the result, that is why it's almost always used in a separate method.
params.permit(:create_special_categories)
What you must do is use what that returns for your following statements
permitted_params = params.permit(:create_special_categories)
Model.create(permitted_params)
...however you really should outsource this to a special method like you already have. You will have to tweak this to your use-case obviously.
def balance_sheet_params
if params[:create_special_categories]
params.permit(:id,
:entity,
:entity_id,
:date,
:name,
:create_special_categories)
else
params.permit(
:id,
:entity,
:entity_id,
:date,
:name)
end
end

How does .valid? run even there is no object in front of it (valid? instead of object.valid?)?

Watching Railscasts, more specifically Form Objects. Here is the code.
Controller code:
def create
#signup_form = SignupForm.new
if #signup_form.submit(params[:user])
session[:user_id] = #signup_form.user.id
redirect_to #signup_form.user, notice: "Thank you for signing up!"
else
render "new"
end
end
Method found on form object:
class SignupForm
def submit(params)
user.attributes = params.slice(:username, :email, :password, :password_confirmation)
profile.attributes = params.slice(:twitter_name, :github_name, :bio)
self.subscribed = params[:subscribed]
if valid?
generate_token
user.save!
profile.save!
true
else
false
end
end
end
I understand most of the code, but what I don't understand is how .valid? can run without an object written directly in front of it (i.e.: object.valid?)? I tried replicating this with Ruby, but Ruby requires an object to be directly written in front of the method, which leads me to believe this is some sort of Rails magic.
Can someone explain how .valid? runs without an object in front of it , and which object it picks up?
I tried using the following Ruby code and did not work:
array = [1,2,3,4]
def meth
if is_a?
puts "is array"
else
puts "not array"
end
end
array.meth => error: wrong number of arguments (given 0, expected 1)
In the Railscast #416 in question, Ryan includes (among others) the ActiveModel::Validations module into the SignupForm class. This module implements the valid? method for the class.
Now, in Ruby you can always call methods on the current object (i.e. self) without explicitly naming the receiver. If the receiver is unnamed, self is always assumed. Thus, in your submit method, valid? in called on the same instance of the SubmitForm where you originally called submit on.
class SignupForm
def submit(params)
user.attributes = params.slice(:username, :email, :password, :password_confirmation)
profile.attributes = params.slice(:twitter_name, :github_name, :bio)
self.subscribed = params[:subscribed]
if valid?
generate_token
user.save!
profile.save!
true
else
false
end
end
def valid? // <--- this is what they are calling.
return true // this is made up... i am sure it does something
end
end

Rails Controller: how do you account for optional and required parameters?

In the tutorials I have seen, create has been implemented like this:
def create
#note = Note.new(note_params)
#note.save
redirect_to #note
end
private
def note_params
params.require(:note).permit(:title, :type, :description, :dueDate)
end
I have read about the fetch method for optional parameters, but how do I mix the two methods to require some parameters and permit others? Would it be like this:
private
def note_params
params.require(:note).permit(:title, :type)
params.fetch(:note, {}).permit(:description, :dueDate)
end
In this case, could I expect to pass 0, 1, or 2 of the fetched params?
You're reading it wrong, I think. In this line
params.require(:note).permit(:title, :type, :description, :dueDate)
The required parameter is :note. And :title, :type and others are simply permitted/allowed to appear under :note. None of them are required by this syntax. If you really need :title to be there, that is best handled by presence validation on your Note model.
class Note
validates_presence_of :title
end
Now, if you don't pass params[:note][:title], #note.save will return false and you can render form with user-friendly errors (highlight missing fields, etc.). You wouldn't be able to do that (as easily) if note_params method raised an exception on missing title attribute. So that is how you handle required record attributes in rails.

ruby on rails: instance variable returns nil

I've been trying to push the input data from my form to the database using the create function, but the instance variable in create function keeps returning 'nil' and after the 'begin transaction', it does 'rollback transaction'
The model function works fine as I get the desired parsed data, and so does the timetables_params function. But timetables_params[:start_time] always returns 'nil' even though the timetables_params returns all the start_time values and end_time values.
How can I fix this?
Here is my controller
def index
#user = current_user
#timetables = #user.timetable.all
end
def new
#timetable = Timetable.new
end
def create
timetables_params[:start_time] = Timetable.parse_timetable_time(timetables_params, 'start')
timetables_params[:end_time] = Timetable.parse_timetable_time(timetables_params, 'end')
#timetable = Timetable.create(timetables_params)
if #timetable.save
flash[:success] = "Done"
else
render 'new'
end
end
private
def timetables_params
params.require(:timetable).permit(:user_id, :start_time, :end_time)
end
end
Here is my model
belongs_to :user
attr_accessor :user, :start_time, :end_time
def self.parse_timetable_time(hash, type)
date_string = hash["#{type}_time(1i)"].to_s + "=" + hash["#{type}_time(2i)"].to_s + "=" + hash["#{type}_time(3i)"]
Time.parse(date_string)
end
You probably have not set the user since its belongs_to :user and i dont see it anywhere in your code. That's why its rolling back and you probably required user_id in your Timetable model. My suggestion is below
Instead of:
#timetable = Timetable.create(timetables_params)
Use build:
#timetable = current_user.timetables.build(timetables_params)
Thanks for all the help above, but turns out that I just had to add the following lines in the model and modify the controller create function:
model
validates :user_id, presence: true
validates :start_time, :end_time, presence: true
controller
def create
#timetable = current_user.timetables.build(timetables_params)
if #timetable.save
flash[:success] = "Done"
else
render 'new'
end
And, I don't necessarily need to parse the datetime values, Rails does do it automatically

Rails datetime_select: 1 error(s) on assignment of multiparameter attributes [error on assignment

How do I get the parameters of datetime_select to save?
Error parameters:
{"utf8"=>"✓",
"authenticity_token"=>"/Tu18E4ubxp0XWcoLTdrm2B4Ho80PDH86dWwm9fvEMs=",
"post"=>{"title"=>"asdf",
"event_date(1i)"=>"2015",
"event_date(2i)"=>"8",
"event_date(3i)"=>"7",
"event_date(4i)"=>"15",
"event_date(5i)"=>"26",
"description"=>"asdf",
"published"=>"0"},
"button"=>""}
The model:
class Spree::Post < ActiveRecord::Base
validates_presence_of :title, :description, :event_date
def event_date
end
scope :published, lambda { where(:published => true) }
scope :latest, order("created_at DESC").limit(3)
end
Relavent controller code:
def create
#post = Spree::Post.new(post_params)
if #post.save
flash[:notice] = "Post saved successfully"
redirect_to admin_posts_path
else
flash[:alert] = "There was an error saving your post"
redirect_to :back
end
end
And the view:
<p><%= f.label :event_date, Spree::Post.human_attribute_name(:event_date) %></p>
<p><%= f.datetime_select :event_date %></p>
The problem seems to be that it's trying to store multiple values. I'm guessing that the fix will be by adding to the model file, right?
Have you permitted event_date in your post_params? (We don't know, because you didn't include your entire posts controller file.) If you haven't already permitted them, you might want to try editing your post_params to look like:
class Spree::PostsController < ActionController::Base
private
def post_params
params.require(:post).permit(:event_date)
end
end
See http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html for more information.
EDIT: Actually, given the snippet of your error message you provided, I'm less confident you have a strong parameters problem. I'll still keep this answer up, though.
You have to explicitly permit each parameter part
def post_params
params.require(:post).permit("event_date(1i)","event_date(2i)","event_date(3i)","event_date(4i"),"event_date(5i)",:any,:other,:post,:fields)
end
You should ensure that your field is a datetime in your database. If it is a string it will throw this error message when you try to save the datetime_select.

Resources