Selecting data in a view and inserting them in Users database - ruby-on-rails

I am reading the contact informations of users from Outlook API, and I would like to add them to my Users database using a submit_tag approach. But it does not work. So far my form on index.html.erb looks like:
<h1>My contacts</h1>
<table class="table">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
<%= form_tag import_contacts_path, method: :put do %>
<%= submit_tag "Import Selected contact" %>
<% #contacts.each do |contact| %>
<tr>
<td> <%= check_box_tag "contact_ids[]", 'Select' %></td>
<td><%= contact.given_name %></td>
<td><%= contact.surname %></td>
<td><%= !contact.email_addresses[0].nil? ? contact.email_addresses[0].address : '' %></td>
</tr>
<% end %>
</table>
<%= submit_tag "Import Selected contactact" %>
<% end %>
My ContactController looks like:
class ContactsController < ApplicationController
include AuthHelper
def index
token = get_access_token
if token
# If a token is present in the session, get contacts
callback = Proc.new do |r|
r.headers['Authorization'] = "Bearer #{token}"
end
graph = MicrosoftGraph.new(base_url: 'https://graph.microsoft.com/v1.0',
cached_metadata_file: File.join(MicrosoftGraph::CACHED_METADATA_DIRECTORY, 'metadata_v1.0.xml'),
&callback)
#contacts = graph.me.contacts.order_by('givenName asc')
else
# If no token, redirect to the root url so user
# can sign in.
redirect_to root_url
end
end
def import
User.create(:first_name => #contacts.givenName , :last_name => #contacts.surname, :email => #contacts.email_addresses)
redirect_to imported_path
end
end
I can read my contact information without any problem, but when i try clicking on the button to import a selection of contact, I have the following error:
NoMethodError (undefined method `givenName' for nil:NilClass):
app/controllers/contacts_controller.rb:26:in `import'
My routes look like
resources 'contacts' do
collection do
put :import
end
Does anyone knows if it is actually possible to create such import function ? Because i am trying to read something that is not on a local database actually.

I ended up creating the following function in the controller:
def import_contact(contact)
Contact.create(email: !contact.email_addresses[0].nil? ? contact.email_addresses[0].address : '', first_name: contact.given_name, last_name: contact.surname, user_id: current_user )
return !contact.email_addresses[0].nil? ? contact.email_addresses[0].address : ''
end
and the the view calls the function: <%= import_contact(contact) %>
This way i unfortunately do not select which conctact i want to import. I import all of them, but that is the best i could find now.

You have called #contacts in
def import
User.create(:first_name => #contacts.givenName , :last_name => #contacts.surname, :email => #contacts.email_addresses)
redirect_to imported_path
end
But you have not define #contacts. Since #contacts is nil and you are calling givenName to nil it is giving error. Can you specify #contacts within import method or before filter so that it would be available with in that method.
Hope defining #contacts will fix the issue. If the issue still exist let me know.
Please check the params, in params the value must have come you can use something like
def import
User.create(:first_name => params[:givenName] , :last_name => params[:surname], :email => params[:email_addresses])
redirect_to imported_path
end
Try this one and let me know if there is any issue. Or you can send what params that comes.

Related

Ruby on Rails search & Result on the same page error

Here the show.html displays a dropdown, which contain Roles.
When we select the role we should able to get permission result in the same page
For that I used partial, but getting error as given in the image,
Without using partial when i tried to display in a separate display.html.erb file , I am getting proper result.
but i want to get result in same show.html.erb file.
Kindly give my some suggestions to attain the proper results
permission_controller
def display
param = params[:role]
id=param[:id]
#roles = Role.includes(:permissions).all
#uniq_controller = Role.joins(:permissions).where('roles.id=?',id).select('permissions.*').group_by { |p| p.description }
redirect_to permissions_show_path
end
def show
#permission = Permission.new
end
show.html.erb
<%= form_tag(:controller => "permissions", :action => "display") do %>
<%= collection_select(:role, :id, Role.all, :id, :name) %>
<button type="submit">search</button>
<% end %>
<th width="25px"> <%= "Controller" %></th>
<th width="25px"> <%= "Permissions" %></th>
<% #uniq_controller.each do |permission| %>
<%= render partial:"display", locals:{permission:permission} %>
<% end %>
_display.html.erb
<thead>
<th width="25px"> <%= permission.first.gsub("_"," ") %></th>
<% permission.second.each do |cont| %>
<tr>
<th width="25px"><%= check_box_tag :permission_ids, {multiple: true},
cont.id %><%= cont.name %></th>
</tr>
<% end %>
</thead>
You haven't defined #uniq_controller in the show action which triggered that error. Just define it in the show action
def show
#permission = Permission.new
#uniq_controller = Role.joins(:permissions).where('roles.id=?',id).select('permissions.*').group_by { |p| p.description }
end
You have not defined #uniq_controller in the show action in permission_controller controller which triggers this error.
I'd recommend that you define a method called uniq_controller in permission_controller as follows:
def uniq_controller(id)
Role.joins(:permissions).where('roles.id=?',id).select('permissions.*').group_by { |p| p.description }
end
and then make it available in your view as a helper method by adding this code to your permission_controller:
helper_method :uniq_controller
So the code in permission_controller should be like:
helper_method :uniq_controller
def display
#roles = Role.includes(:permissions).all
redirect_to permissions_show_path
end
def show
#permission = Permission.new
end
def uniq_controller(id)
Role.joins(:permissions).where('roles.id=?',id).select('permissions.*').group_by { |p| p.description }
end
Then in your view show.html.erb replace:
#uniq_controller.each
with:
uniq_controller(params[:role][:id]).each
This should fix the error that you are getting and follows Rails practices, for more details about helper_method please refer to:
https://apidock.com/rails/ActionController/Helpers/ClassMethods/helper_method
One more recommendation is to rename permission_controller to permissions_controller to follow Rails resources/controller naming convention.

Custom Controller Method, Route, & ERB

I have a search form and I need to be able to filter based on whether or not pets are allowed, but I'm not sure how to accomplish this. I have setup a route, a controller method, and a button but none of that seems to be working.
listings_controller:
def pets_allowed
#listings = #listings.where(pets: true)
end
routes.rb:
get "pets_allowed" => "listings#pets_allowed"
html.erb file:
<div>
<%= link_to 'Pets Allowed', pets_allowed_path, :class => 'button btn-transparent' %>
</div>
Maybe you meant
def pets_allowed
#listings = Listing.where(pets: true)
end
This is a basic example of another way to do what I think you're aiming for (as per comments).
This adds a new action in your Listings controller that returns a filtered list of results based on the users input from the search form on your listings index page. The results are rendered using the same index template. The logic for checking/retrieving results can be modified based on what you want. If you just want a check box, only have a checkbox or a button that calls the action.
You could do similar logic but use ajax to return the results and render them on the index template using a partial.
This should give you enough information to google for examples/tutorials and try different ways of getting what you want.
Add a route:
# routes.rb
get 'pets_allowed', to: 'things#pets_allowed'
Add a new action:
# listings_controller.rb
# GET /things
# GET /things.json
def index
#listings = Listing.all
end
# Get /pets_allowed
def pets_allowed
#listings = Listing.where("name LIKE ? and pets = ?", "%#{params[:name]}%", params[:pets] )
render template: "listings/index", variable: #listings
end
Add a search form to your view:
# listings/index.html.erb
<h1>Listings</h1>
<%= form_tag('pets_allowed', method: 'GET' ) do %>
<%= label_tag :name %><br>
<%= text_field_tag :name %>
<br>
<%= label_tag :pets %><br>
<%= check_box_tag :pets, 't' %>
<br>
<%= submit_tag("Search") %>
<% end %>
<table>
<thead>
<tr>
<th>Listing name</th>
</tr>
</thead>
<tbody>
<% #listings.each do |listing| %>
<tr>
<td><%= listing.name %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Listing', new_listing_path %>

Pass an array of user_params to update in rails

I am trying to bulk update users, and in so, passing an array of user information to user_params. I know(/believe) this is the issue, but I don't understand how to solve it, it keeps giving me the error of 'ArgumentError in UsersController#update_all - wrong number of arguments (1 for 0)'
I believe the question I'm asking is, how do I optionally pass an array to user_params for a bulk update, but can also send it a single user's information. Any information is appreciated to understand where I'm missing what is happening.
Thanks!
users_controller.rb
def update_all
params["user"].keys.each do |id|
#user = User.find(id.to_i)
#user.update_attributes(user_params(id))
end
redirect_to(users_path)
end
def user_params
params.require(:user).permit:first_name, :last_name, :email, :password, :password_confirmation, :role_id, :approved)
end
Form
<h1>Editing users</h1>
<%= form_for :user, :url => update_all_path, :html => { :method => :put } do %>
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>E-Mail</th>
</tr>
<% #users.each do |user| %>
<%= fields_for "user[]", user do |user_fields| %>
<tr>
<td><%= user_fields.text_field :first_name %></td>
<td><%= user_fields.text_field :last_name %></td>
<td><%= user_fields.email_field :email %></td>
<td><%= user_fields.check_box :approved %></td>
</tr>
<% end %>
<% end %>
</table>
<div class="actions">
<%= submit_tag %>
</div>
<% end %>
<%= link_to 'Back', users_path %>
You're trying to call user_params with an argument, but that method (def user_params) takes no argument.
Since you've set up your form to send multiple users, params[:user] look like this:
{
"1"=>{"first_name"=>"K", "last_name"=>"P", "email"=>"k#", "approved"=>"1"},
"2"=>{"first_name"=>"A", "last_name"=>"Q", "email"=>"a#", "approved"=>"0"}
}
So the simplest thing to do is run each on that whole Hash instead of on .keys:
params["user"].each do |id, attributes|
User.find(id).update_attributes(attributes)
end
That avoids your strong parameter requirements, though, but you're going to need to do a little more work in there to handle the whole hash. After requiring :user, you need to permit fields on each value in that hash:
def bulk_user_params
users = params.require(:user).permit!
users.each do |id, attributes|
users[id] = attributes.permit(:first_name, :last_name, :email, :approved)
end
end
The permit! allows any keys in params[:user], which you need because those keys are 1, 2, etc. Then the looped permit and assignment filters the attribute hashes down to what you expect.
Once the new, safe hash is constructed, use it in update_all instead of the basic user_params:
bulk_user_params.each do |id, attributes|
User.find(id).update_attributes(attributes)
end
#user.update_attributes(user_params(id))
should be
#user.update_attributes(user_params)

Rails getting the error: First argument in form cannot contain nil or be empty

I've been getting this error for a couple days and I'm totally blocked. I tried redoing the model (I'm following the rails starting guide) and just not getting anywhere.
First argument in form cannot contain nil or be empty
I have time_delta as a nested class of stock im trying to create a form to view and create new time_deltas on a stock's show and I keep getting the above error.
Heres my time_delta controller:
class TimeDeltasController < ApplicationController
def new
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build
respond_with(#time_delta)
end
def create
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build(params[:stock])
#time_delta.save
end
end
Heres my view for the specific stock
<h1> Stock </h1>
<table>
<tr>
<th>Stock</th>
<th>Hashtag</th>
</tr>
<tr>
<td><%= #stock.name %></td>
<td><%= #stock.hashtag %></td>
</tr>
</table>
<h2>Deltas: </h2>
<table>
<tr>
<th>Stock</th>
<th>Hashtag</th>
</tr>
<% #stock.deltas.each do |delta| %>
<tr>
<td><%= #delta.start %></td>
<td><%= #delta.length %></td>
</tr>
<% end %>
</table>
<h2>Add a TimeDelta:</h2>
<%= form_for([#stock,#time_delta]) do |f| %>
<p>
<%= f.label :start %><br>
<%= f.text_field :start %>
</p>
<p>
<%= f.label :length %><br>
<%= f.text_area :length %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', stocks_path%>
<%= link_to 'Edit', edit_stock_path(#stock)%>
Heres how I added the route in my routes.rb:
resources :stocks do
resources :time_deltas
end
Any information would be greatly appreciated, I'm really stuck.
EDIT: Stocks controller stuff
def show
#time_delta = #stock.time_deltas.build
#stock = find_stock
end
private
def find_stock
return Stock.find(params[:id])
end
You are trying to access #time_delta variable in your stocks/show view, but it is not set. Add the following line to StocksController#show action.
#time_delta = #stock.time_deltas.build
EDIT:
Also there is a problem with the naming of your TimeDelta model, because in Ruby 'delta' is plural of 'deltum'. To adhere to Rails conventions, change the the model name to TimeDeltum or alternatively tell Rails to use 'deltas' as the plural form of 'delta'. You can learn how to do it here.
The error basically means you've not set the variables for use in form_for
As you're a beginner, let me explain how it works:
form_for is basically an instance method (helper) which takes ActiveRecord objects, and outputs them into an HTML form. Your definitions of elements (f.____field) are for the method to determine which HTML to output
Like all methods, form_for has arguments/parameters which it relies on to help the method run correctly. The parameters for form_for include a correctly formatted ActiveRecord object, which is why you have to call Model.new each time you want to use it
Your error means the method cannot process the variables (objects) you've sent, either from lack of data (empty) or non-existence (nil). To fix this, as #vee has mentioned, you need to make sure your form_for is receiving the correct data
I would try this:
class TimeDeltasController < ApplicationController
def new
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build
respond_with(#stock, #time_delta)
end
def create
#stock = Stock.find(params[:stock_id])
#time_delta = #stock.time_deltas.build(params[:stock])
#time_delta.save
end
end
You should read up on respond_with to see how it works

My controller is -persistently- sending wrong params[:id] in Rails?!

I'm new to Ruby on Rails & to web programming.
In my application I have two models; Directorate which has_many :users, and User which belongs_to :directorate.
When creating a new user, I use <%= f.collection_select(:directorate_id,Directorate.all, :id, :name) %> in the new.html.erb form to assign the new user to specific directorate. However, I want to build a user-friendly interface for the dba that lists all directorates; and listing all users beside each directorate, with a link to assign any user to a specific directorate.
What I did is the following:
In Directorate model, I defined the following function:
def assign_user!(user)
user.update_attributes(directorate_id: #directorate)
end
and in the directorates controller, I defined the following action:
def assign_user
#directorate = params[:directorate]
assign_user! params[:user]
redirect_to directorates_url
end
Now, directorates/index.html.erb contains the following:
<h1>Listing directorates</h1>
<table>
<tr>
<th>Name</th>
<th>Info</th>
</tr>
<% #directorates.each do |directorate| %>
<tr>
<td><%= directorate.name %></td>
<td><%= directorate.info %></td>
<td><%= link_to 'Show', directorate %></td>
<td><%= link_to 'Edit', edit_directorate_path(directorate) %></td>
<td><%= link_to 'Destroy', directorate, confirm: 'Are you sure?', method: :delete %></td>
<%= #directorate = directorate%>
<%= render 'users_form' %>
</tr>
<% end %>
</table>
<br />
<%= link_to 'New Directorate', new_directorate_path %>
and, -users_form.html.erb contains the following form (which is supposed to list all users beside each directorate, with a link to assign any user to a certain directorate):
<h1>Listing Users</h1>
<table>
<tr>
<th>User Name</th>
</tr>
<% #users.each do |user| %>
<tr>
<td><%= user.username %></td>
<td><%= link_to 'Assign to Current Directorate', {controller: 'directorates', action: 'assign_user', directorate: #directorate, user: user}, :method => :put %></td>
</tr>
<% end %>
</table>
<br />
Here is the problem, when listing directorates & click on the 'Assign to Current Directorate' I receive the following error:
http://127.0.0.1:3000/directorates/assign_user?directorate=4&user=5
ActiveRecord::RecordNotFound in DirectoratesController#update
Couldn't find Directorate with id=assign_user
Rails.root: /home/ehab/sites/IAMS
Application Trace | Framework Trace | Full Trace
app/controllers/directorates_controller.rb:61:in `update'
Request
Parameters:
{"_method"=>"put",
"authenticity_token"=>"L5tz3hv2IW0meE79qUq0/tjfGKwDlpC23hOeAWtmTvk=",
"directorate"=>"4",
"user"=>"5",
"id"=>"assign_user"}
It's clear that the params is submitting "id"=>"assign_user" which I don't want, what i want is "id"=>"directorate.id" (4 in the above example). What shall I do to fix this issue?!
first of all your routes should say that assign_user is a member method on a certain directorate object:
resources :directorates do
member do
put :assign_user
end
end
second you say you define assign_user! in Directorate model and assign_user in DirectoratesController but both methods imply that they share same object state like instance variable #directorate which is not true
your controller method assign_user should look vaguely like
def assign_user
#directorate = Directorate.find params[:id]
#user = User.find params[:user_id]
#directorate.assign_user! #user
end
and model method should look like
def assign_user!(user)
user.update_attributes(directorate_id: self.id)
end
and even that i would switch around to instead of telling Directorate to change user's attributes you would tell User to assign itself to whatever controller wants.
and the final bit is your link that assigns user to directorate:
link_to 'Assign to Current Directorate',
assign_user_directorates_path(#directorate, :user_id => user)
0 lines of code above were tested for even syntactical correctness, DO NOT copy-paste, read and understand

Resources