Can't get my strong parameters nested correct in Ruby on Rails
As per rails documentation Nested attributes allow you to save attributes on associated records through the parent
. So in your strong params you need to pass attributes like this.
params.permit(:name, :description, task_attributes: [:name, :start, :end])
I suggest you to bind all params under one attribute like this
params.require(:project).permit(:name, :description, task_attributes: [:name, :start, :end])
so you must send params from frontend like
{"project": {"name"=>"asdf", "description"=>"zxvccxvzzxcvxcvcxvzxcvz", "task_attributes"=>[{"start"=>"2019-12-05T03:38:48.555Z", "end"=>"2019-12-14T03:38:48.555Z", "name"=>"Some task"}]}}
You can read the documentation from https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
How to pass an array between Ruby files
You can't pass an array from a ruby file to another one., you only can pass data between classes and objects.
Other possibilities which may help:
- constants (Defined with starting capital letter)
- global variables (starting with $)
- Singletons
To keep data inside the class instances (objects) you need attributes (variables starting with @
).
You can find this concepts in every beginner manual of ruby (and if not, then the manual is not worth to be used)
You made another common error.
Let's check it with a small example:
class Company
attr_accessor :jobs
def initialize()
jobs='This should be assigned to my accessor jobs'
end
end
puts Company.new.jobs
The result is an empty line.
What happend? In the initialize
-method you define a local variable jobs
. Local means, it is only available in the method ans is lost when the method leaves.
Correct would be 1) using the instance variable:
class Company
attr_accessor :jobs
def initialize()
@jobs='This should be assigned to my accessor jobs'
end
end
or 2) using the accessor method:
class Company
attr_accessor :jobs
def initialize()
self.jobs='This should be assigned to my accessor jobs'
end
end
In both cases the puts Company.new.jobs
returns the text you defined.
See also Ruby instance variable access
Ruby on Rails: finding a model instance from a different controller
Simplest way is add the id as a hidden field. Your strong params should take care of project_id it looks like:
<%= form_for @invitation do |f| %>
<%= f.hidden_field :project_id, @project.id %>
<%= f.collection_select :user_id, User.all, :id, :first_name %><br>
<%= f.submit "Send Invitation", class: "btn btn-primary" %>
<% end %>
Then in your controller, just use the params to make a new one. Passing the id through the new method will associate the record for you.
def create
@invitation = Invitation.new invitation_params
if @invitation.save
flash[:success] = "Invitation sent!"
redirect_to @invitation
else
render 'new'
end
end
Also note, when you call create_invitation
that actually calls the create method right there. So it's already saved. The corresponding to new
where it's just built in memory is build_invitation(invitation_params)
Passing in an array into form_for() and link_to()
Nesting resources route from an URL that contains the ID of both resources, in this case something like: /projects/1/tickets/10
. To generate this URL, we need to know the id of both the project and the ticket, so both of these objects need to be passed in.
An edit URL goes further, and adds an action keyword - /projects/1/tickets/10/edit
, so again we need to pass in this action.
A RESTful destroy route in Rails, however, uses the HTTP method DELETE instead of an action keyword, so the URL to destroy your ticket really is /projects/1/tickets/10
; just with a DELETE request instead of GET.
For more information, I'd recommend reading through Rails Routing from the Outside In
Rails 4: How to use includes() with where() to retrieve associated objects
The user
object is not part of the project
object, so you won't be able to view it on the project: rather, by saying Project.includes(:user)
, you're telling Rails to eager-load the referenced association when it finds the project. This saves you a database call down the road. For example, non-eagerly:
@project = Project.where(id: params[:id]).first # one database call, fetching the project
@project.user # another database call, fetching the user
And eagerly:
@project = Project.includes(:user).where(id: params[:id]).first # one database call, fetching both project and user
@project.user # no database interaction
This matters more with has_many
queries where eager-loading associations can save N+1 database queries.
You can verify this is working appropriately by calling @project.user
at some point after the eager load and checking your logs: you should see that there was no database call at that point.
Related Topics
Adding to the Value in a Hash Table
Check If a Table Exists in Rails
Cocoapods Not Working in MACos High Sierra
Ruby on Rails: Adding Columns to Existing Database
Jruby on Rails VS. Ruby on Rails, What's Difference
Listen Error: Unable to Monitor Directories for Changes
How to Write the JSON Schema If JSON Has Multiple Data Set
Using --No-Rdoc and --No-Ri with Bundler
Should I Specify Exact Versions in My Gemfile
How to Implement Injection in Ruby
Recurring Billing with Rails and Activemerchant: Best Practices, Pitfalls, Gotchas
Override Vagrant Configuration Settings Locally (Per-Dev)
How to Insert Erb-Tags with Vim