Rails: Create a new record with link_to - ruby-on-rails-4

When the user clicks the link "New Week", a new record of the model week should be created and appended to the end of the list.
Here is my view weeks/index.html.erb
<h1> Weeks </h1>
<%= link_to "New Week", action: :create, method:"post" %>
<% #weeks.each do |week| %>
<ul>
<li> <%= link_to week.id, week %> </li>
</ul>
<% end %>
I am also not quite sure what to put in the create action for the weeks controller. This is what I have so far. The view above is routed to be the root.
def create
#week = Week.create(params[:week])
redirect_to root_path
end
When I click the link, it submits a POST action, but nothing else happens. A new record is not created. My debug(params) look like this.
--- !ruby/hash:ActionController::Parameters
method: post
action: index
controller: weeks
Update
I got it to work by doing
<%= link_to "New Week", { action: :create, :id => Week.new }, method:"post" %>
but I'm not sure if this is the correct way to go about it. Can anyone with expertise expand upon what is happening here?

Related

Issue with param not pushing data to database in Rails

Quick one. I'm trying to push a parameter into the database when i'm creating an object. I have it working if I force the integer as with the commented code below however for whatever reason I cannot get it to be added to the database is I use the params[:subscription_id] method. I can see the parameters in my server but cannot see it getting inserted into the certificates table. If i force the integer in my controller it will go through and I can see the subscriptions_id getting passed in.
Does this have any reason to do with my relationship being a has_one relationship perhaps?
Certificate Controller
class CertificatesController < ApplicationController
def new
#certificate = Certificate.new
end
def create
#certificate = Certificate.new(certificate_params)
#certificate.subscription_id = params[:subscription_id]
##certificate.subscription_id = 1
if #certificate.save
flash[:success] = "The certificate has been uploaded"
redirect_to :back
else
render 'new'
end
end
private
def certificate_params
params.require(:certificate).permit(:document, :title, :subscription_id)
end
end
View code:
<%= link_to "upload certificate", new_certificate_path(subscription_id: subscription.id) %>
Models
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :course
has_one :certificate
end
class Certificate < ActiveRecord::Base
belongs_to :subscription
has_attached_file :document
#validates_attachment :document, content_type: %w(application/pdf application/msword application/vnd.openxmlformats-officedocument.wordprocessingml.document)
do_not_validate_attachment_file_type :document
end
Certificate Form
<div class="row">
<div class="site-forms">
<div class="col-md-10">
<%= simple_form_for #certificate do |f| %>
<!-- <= f.input :course_img, as: :file, required: true, label: "Please upload a brand image for your course" %><br> -->
<span class="btn btn-default btn-file">
<i class="fa fa-cloud-upload fa-lg"></i> Upload Image
<%= f.input :document, as: :file, required: true, label: false %>
</span> Please upload Certificate as PDF <br><br>
<%= f.input :title, placeholder: "Course Title", required: true, label: "Course Title" %>
<%= f.button :submit, class: "btn btn-primary" %>
<% end %>
</div>
</div>
</div>
This is probably something stupid i'm missing but I can get it to work if I force the integer in the commented out code in the controller. I'm nearly sure the params code is correct. Thanks.
Added logs
Started POST "/certificates" for ::1 at 2017-05-23 20:40:30 +0100
Processing by CertificatesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"6fV0xLOoy6ppNG7PYp37vkKqJnxU17nLPSK/mvbgH8k3s2LyaMEOJlekq5S0Ed4fpbNcqVe+cBsu5F38ACCmcg==", "certificate"=>{"document"=>#<ActionDispatch::Http::UploadedFile:0x007f954362c160 #tempfile=#<Tempfile:/var/folders/gx/86yj74bx3md88cfn2fwc975h0000gn/T/RackMultipart20170523-5261-1n2mwfl.png>, #original_filename="duck.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"certificate[document]\"; filename=\"duck.png\"\r\nContent-Type: image/png\r\n">, "title"=>"Test"}, "commit"=>"Create Certificate"}
Command :: PATH=/usr/local/bin/:$PATH; file -b --mime '/var/folders/gx/86yj74bx3md88cfn2fwc975h0000gn/T/36846677e3a8f4c0b16d8bdf8ef1860820170523-5261-e90bny.png'
(0.1ms) begin transaction
Command :: PATH=/usr/local/bin/:$PATH; file -b --mime '/var/folders/gx/86yj74bx3md88cfn2fwc975h0000gn/T/36846677e3a8f4c0b16d8bdf8ef1860820170523-5261-1d907er.png'
SQL (0.3ms) INSERT INTO "certificates" ("document_file_name", "document_content_type", "document_file_size", "document_updated_at", "title", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["document_file_name", "duck.png"], ["document_content_type", "image/png"], ["document_file_size", 49114], ["document_updated_at", "2017-05-23 19:40:30.662715"], ["title", "Test"], ["created_at", "2017-05-23 19:40:30.683041"], ["updated_at", "2017-05-23 19:40:30.683041"]]
(0.7ms) commit transaction
Redirected to http://localhost:3000/certificates/new?subscription_id=3
Completed 302 Found in 36ms (ActiveRecord: 1.1ms)
Started GET "/certificates/new?subscription_id=3" for ::1 at 2017-05-23 20:40:30 +0100
Processing by CertificatesController#new as HTML
Parameters: {"subscription_id"=>"3"}
Rendered certificates/_form.html.erb (7.7ms)
Rendered certificates/new.html.erb within layouts/application (8.7ms)
Rendered shared/_message.html.erb (0.1ms)
Completed 200 OK in 95ms (Views: 94.3ms | ActiveRecord: 0.0ms)
You need to set your subscription_id in a hidden field so that it gets passed in the params hash.
<%= f.hidden_field :subscription_id, :value => params[:subscription_id] %>
That way it gets set with the rest of the params.
Params are strings. Try
#certificate.subscription_id = params[:subscription_id].to_i
Try change this function as below
def certificate_params
params.require(:certificate).permit(:document, :title, :subscription_id, :subscription)
end
Maybe allow permit subscription field from params.

rails4-autocomplete with belongs to association

I want to implement autocomplete via rails4-autocomplete
Rails 4.2.4
Here is the controller
app/controllers/samples_controller.rb
class SamplesController < ApplicationController
autocomplete :patient, :code
Here is the route file,
config/routes.rb
resources :samples do
get :autocomplete_patient_code, on: :collection
end
And that's the view
app/views/samples/_form.html.erb
<div class="field">
<%= f.label :patient_code %><br>
<%= f.autocomplete_field :patient_id, autocomplete_patient_code_samples_path %>
</div>
With this code I mange to get the autocomplete
However I get invalid foregin key error when try to save the sample that's because the patient's code is passed to the foregin key instead of ID. How do I fix this?
Here is the request Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"blabla",
"sample"=>{"patient_id"=>"A123",
"commit"=>"Create Sample"}
Get "/samples/autocomplete_patient_code?term=A12" returns
{"id":"15","label":"A123","value":"A123"}]
After reading the GitHub documentation of rails4-autocomplete, I devised the following solution:
Add attr_accessor :patient_name to your Sample model and modify the form as follows:
...
<%= f.autocomplete_field :patient_name, autocomplete_patient_code_samples_path, id_element: '#patient_id' %>
<%= f.hidden_field :patient_id, id: 'patient_id' %>
...
With this change whenever you select any patient name, that patient's ID will be updated on the hidden field and it will be submitted as patient_id.
Hope this solves your problem.
Source: Github

Rails - loops and routes, and getting . instead of /

I have three controllers, books, users and contributions. In a view in the books controller I have the following snippet -
<%= link_to contrib.user.username, show_users_path(contrib.user_id) %>
Which returns /users.n rather than /users/n
<%= link_to contrib.user.username, "users/#{contrib.user_id}" %>
does the same thing.
I've read SO questions about this problem with nested resources, and with custom routes, but I've simply got my routes set up as resources, as follows -
devise_for :users, :controllers => { registrations: 'registrations' }
resources :blogs
resources :books
resources :users
resources :contributions
In users/index I have the snippet
<%= link_to user.username, "users/#{user.id}" %>
which works fine. What is going on?
.....
The problem was I'm using an each loop. The whole snippet goes
<% if controller.controller_name == "books" %>
<p><strong>by <%=link_to book.user.username, book.user %></strong></p>
<% book.contributions.each do |contrib| %>
<p><%= link_to contrib.user.username, user_path(contrib.user) %></p>
<%end%>
<% end %>
I changed the fourth line to this -
<p><%= link_to contrib.user.username, user_path(book.contrib.user) %></p>
Which works. Can anyone explain why?
It's because the default path for the show action is object_path(object_id) - there i no default route called show_object_path - I was confusing the path with action.

Rails object method returning full array

I'm having an issue with an association. I've got an Employee model that belongs_to a Role model. When I try to display the association, I get the full array displayed back.
Here's the show action from my Employee controller. As you can see, I've tried a few different methods to make the proper association in the first place:
def show
#employee = Employee.find(params[:id])
# #role = Role.where(:id => #employee)
# #role = Role.find_by_sql("select roles.role_title from roles where roles.id in (select role_id from employees where role_id='1')")
#role = Role.where(id: #employee)
end
And here's the view:
<p>
<strong>Role:</strong>
<%= #role.each do |r|
r.role_title
end %>
</p>
My output comes back as:
Role: [#<Role id: 3, role_title: "Support Engineer", created_at: "2014-08-20 16:09:22", updated_at: "2014-08-20 16:09:22">]
What am I missing here?
You need to actually iterate and display something for each role.
<%= %> means "display the result of the expression", which in your case, is an each.
each returns the collection you were iterating over. You want something closer to:
<% #role.each do |r| %>
<%= r.role_title %><br/>
<% end %>
Although it obviously depends on what you actually want to display, for example:
<%= #role.collect(&:role_title).join(', ') %>
Unrelated: I might argue that Role#role_title is redundant and Role#title would be sufficient.
If the employee belongs_to a role there is only one role for each employee.
You can retrieve it as easily as specifying...
#employee.role
but if you insist on constructing a separate retrieval then
#role = Role.where(id: #employee.role_id).first
EDIT
So talking about the views... if there's only one #role you don't need to iterate through an array...
<p>
<strong>Role:</strong> <%= #role.role_title %>
</p>
You're seeing an array because the where returns an array, you could bypass that with...
#role = Role.where(id: #employee).first
As Dave Newton pointed out, if it really was an array you'd need to do...
<p>
<strong>Role:</strong>
<% #role.each do |r| %>
<%= r.role_title %>
<% end %>
</p>

Showing Spree taxonomy tree on product page

I'm running Spree 2.2. I'm trying to get the standard taxonomy/filter list to appear on each individual product page in Spree, but I cannot find where it decides that there's sidebar content to be displayed. If anyone can shed any light on where/how that's decided I'd be most grateful.
On the front-end part of spree, more specific, on the index view of the products controller, route spree_frontend/app/views/spree/products/index.html.erb at the beginning of the file, it get's decided whether there will be displayed the taxons or not:
<% content_for :sidebar do %>
<div data-hook="homepage_sidebar_navigation">
<% if "spree/products" == params[:controller] && #taxon %>
<%= render :partial => 'spree/shared/filters' %>
<% else %>
<%= render :partial => 'spree/shared/taxonomies' %>
<% end %>
</div>
<% end %>
So what you can do is to write an override pointing at any part of the products/show view, in particular i suggest after the product_left_part_wrap" data-hook, wich is a wrapper for the sidebar on the products show view, so your deface could look something like this:
Deface::Override.new(
:virtual_path => 'spree/products/show',
:name => 'add_map_to_product_show',
:insert_after => '[data-hook="product_left_part_wrap"]',
:partial => "spree/products/the_taxons_and_filters"
)
And inside the file named _the_taxons_and_filters.html.erb located on app/views/spree/products/ you can add the code from above and include the taxons filters. Hope this was helpful.