I'm building a basic admin rails application for a Service I use to make creating new users more efficient. Right now, I'm doing it manually, within the application, and it has some tedious steps that I'd like to automate.
The service considers users as "Members"
So I've created a Members scaffold in my rails project which has the same parameters as members do in the Service.
Instead of entering some data in the Service application, I want to do that in my app. So I have a form with several parameters that create a Member and save those parameters: :usname :usemail :usstudio_uid
Next, I want to POST to the Service API with the initial fields that were entered to create an "invitation" for the new member.
I'm trying to do that by calling on a HTTParty function in my Member's Show view.
My form is saving the parameters correctly, I'm connecting to the Service API via HTTParty and creating an invitation OK, but the Member parameters I want to send aren't populating. Instead it's turning what I thought was a reference to the parameter in plain text.
Snippet of that function:
:body => {"callback_url" => "https://foo.com/#invitations",
"consumer_key" => "my consumer_key", "email" => :usemail,
I want :usemail to reference the parameter of the Member being referenced in the show page(i.e. cliff#foo.com). Instead, as you'll see below, the Service API instead thinks the parameter is a string, returning "usemail" as the email parameter, not that of the Member object I want to reference.
I'm pretty new to rails and coding, so it's probably an obvious answer, but I spent a good 6 hours yesterday trying to figure it out. Help! :)
members.rb model:
class Member < ActiveRecord::Base
end
members_controller rb:
Class MembersController < ApplicationController
before_action :set_member, only: [:show, :edit, :update, :destroy]
respond_to :html
def index
#members = Member.all
respond_with(#members)
end
def show
#member = Member.find(params[:id])
end
def new
#member = Member.new
respond_with(#member)
end
def edit
respond_with(#member)
#member.save
end
def create
#member = Member.new(member_params)
#member.save
respond_with(#member)
end
def update
#member.update(member_params)
respond_with(#member)
end
def destroy
#member.destroy
respond_with(#member)
end
private
def set_member
#member = Member.find(params[:id])
end
def member_params
params.require(:member).permit(:usname, :usemail, :usphone, :uspassword, :usconfirm_password, :usinvitation_uid, :usstudio_uid, :uscallback_url, :usmember_uid, :ususername, :usaccess_token)
end
end
In my members_helper.rb:
def getinvitation(member)
result = HTTParty.post "https://foo.com/api/v2/studios/studio_uid/invitations", :body => {"callback_url" => "https://foo.com/#invitations",
"consumer_key" => "my consumer_key", "email" => :usemail,
"name" => :usname, "studio_uid" => :usstudio_uid
}.to_json, :headers => {'X-Auth-Token' => "my token"}
JSON.parse(result.body)
x = ActiveSupport::JSON.decode(result.body)
end
I call on the function in the member's show path:
views/members/show.html.erb
<%= getinvitation(#member) %>
Here is the response I get:
{"uid"=>"29ad0740f4aa47d788bb2a34e9ab7d78", "studio_uid"=>"ORfspJitFbVG",
"date_sent"=>"Sun Feb 1 16:49:21 2015", callback_url"=>"https://app.ustudio.com/#invitations?
invitation_uid=29ad0740f4aa47d788bb2a34e9ab7d78&studio_uid=ORfspJitFbVG",
"consumer_key"=>"my consumer_key", "email"=>"usemail", "name"=>"usname"}
Basically, this is what I was looking for
"email" => member.usemail not :usemail or "usemail"
Related
I am a .NET developer and need to work on a API built in Ruby. Following is the API Code. Can anybody help me in getting the endpoint to it.
class Api::SessionsController < ApplicationController
respond_to :json
skip_before_filter :verify_authenticity_token
before_filter :protect_with_api_key
def update
status = true
participant_ids = []
unless params[:participants].blank?
params[:participants].each do |participant_data|
participant = Participant.where(participant_id: participant_data['participant_id']).first
unless participant.present?
status = false
participant_ids << participant_data['participant_id']
else
activity_records = participant_data['cumulative_time']['activity_records']
participant_data['cumulative_time']['activity_records'] = [] if activity_records.nil?
participant.participant_sessions.new(participant_data['cumulative_time'])
participant.save!
end
end
end
if status
render :json => {status: "OK"}
else
render :json => {error: "No participant with id # {participant_ids.join(',')}"}, :status => 422
end
end
end
I have tried to work with following way /api/sessions/
Pass the required key
passing the
participant parameter with PUT Request like below
{"participants":[{"first_name":"Demo", "last_name":"User", "email":"demouser#demouser.com", "password":"RubyNewBie","postal_code":"160055", "coordinator_name":"RubyNewBie", "coordinator_email":"info#RubyNewBie", "coordinator_phone":""}]}
Please guide me.
Thanks and Regards
By default, update action routes to /api/sessions/:id, so you should make query to that url. Also make sure that you have your route for session set up in routes.rb
Edit:
namespace :api do
resources :participants do
resources :sessions
end
end
If it looks like that, then you're using nested routing. Check:
http://guides.rubyonrails.org/routing.html#nested-resources
You'll have to use the url /api/participants/:participant_id/sessions/:session_id under that setting.
I am using Can.js to create a new record, and it sends a POST /todos to the local Rails server (rails 3.2.13).
The form data in the request is title=mow+lawn&completed=true which is:
title: mow lawn
completed: true
so in the TodosController, the create action, the default code is:
#todo = Todo.new(params[:todo])
but of course, the params[:todo] is empty, and only params[:title] and params[:completed] exist. So I can use
#todo = Todo.new(:title => params[:title], :completed => params[:completed])
to do it, but is there a way to make it somehow automatically create such a param or an object from those params?
Someone suggested in How can can.js add a record to a Rails server?
class TodosController < ApplicationController
wrap_parameters :todo
but I tried each of
wrap_parameters
wrap_parameters :todo
wrap_parameters :todo, :include => [:name, :complete],
wrap_parameters :include => [:name, :complete]
and still Todo.new(params[:todo]) won't work. How does it actually work or any other method to pack the params into an object automatically?
You can use
#todo = Todo.new(params.slice(:name, :completed))
To make it automatic, I guess you could slice the accessible_attributes method for the model:
#todo = Todo.new(params.slice(*Todo.accessible_attributes))
I have a model called Student, which has an attribute called University_ID in it.
I created a custom action and route which displays the details of a specific student via the following link :students/2/detailsi.e. students/:id/details
However, I want to be able to allow the user to use their university ID instead of the database ID so that the following would work for instance students/X1234521/details
i.e. students/:university_id/details
My route file looks like this at the moment:
resources :students
match 'students/:id/details' => 'students#details', :as => 'details'
However this uses the Student_ID as opposed to the University_ID, and I've tried doing
match 'students/:university_id/details' => 'students#details', :as => 'details', but that only corresponds to the Student_ID, not the University_ID.
My controller looks like this, if this helps in any way:
def details
#student = Student.find(params[:id])
end
I also tried doing #student = Student.find(params[:university_id]) but nope, nothing worked.
After chatting with #teenOmar to clarify the requirements, here's the solution we came up with, which allows for the existing students/:id/details route to accept either an id or a university_id (which starts with a w), and uses a before_filter to populate #student for use in various controller actions:
class StudentsController < ApplicationController
before_filter :find_student, only: [:show, :edit, :update, :details]
def show
# #student will already be loaded here
# do whatever
end
# same for edit, update, details
private
def find_student
if params[:id] =~ /^w/
#student = Student.find_by_university_id(params[:id])
else
#student = Student.find(params[:id])
end
end
end
I have Users that have many People that have many Projects.
For example, a new project can be created like this:
def new
#project = Project.new(:person_id => params[:person_id])
#title = "New project"
end
How can I make sure that a user can only insert a person_id here that really belongs to him?
get user_id from session(server side), but not the parameter (client side), e.g.
def new
#project = Project.new(:person_id => session[:current_user_id])
end
or, make the interface more restrict:
def new
#project = Project.create_for_current_user(session)
end
def Project.create_for_current_user(session)
return Project.new(:person_id => session[:current_user_id])
end
Consider using implicit authorization for this. Your end result should look like:
# GET people/1/projects/new
def new
user = User.find(session[:current_user_id])
#project = user.people.find(params[:person_id]).projects.build(:title => "New Project")
end
# POST people/1/projects
def create
user = User.find(session[:current_user_id])
user.people.find(params[:person_id]).projects.create(params[...])
end
Then in routes.rb:
resources :people do
resources :projects
end
With this approach, the new project will be attributed to the user automatically.
On a side note, you should consider using something like Devise or a before_filter so you can access the current user more conveniently without having to do User.find in each action.
And additionally, you should not have an additional #title variable in your controller action. Each controller action should be responsible for sharing a resource or collection of resources.
I have the following in my controller for Attachment
def upload
#attachment = Attachment.build(:swf_uploaded_data => params[:attachment][:attachment], :user_id => current_user.id, :project_id => params[:space_id])
....
end
What I'd like from CanCan is to only allow users to upload to a project_id they belong to. I confirmed the controller is getting the correct info, no nils
Here is my cancan:
can :upload, Attachment do |attachment|
Rails.logger.info 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX- include CanCan::Ability - ATTACHMENT'
Rails.logger.info attachment.inspect
Rails.logger.info attachment.project
current_user.try(:role, attachment.space)
end
Problem here, is that attachment. is nil, and attachment.project is nil? How do you solve for this issue with CanCan so I can make sure only project teammembers can upload attachments to the project?
Thank you
I think the best approach it to do it at a lower level with the authorize! method that the Controller action.
So ...
#AttachmentController
#Will remove it from cancan
load_and_authorize_resource :except => [:upload]
def upload
#attachment = Attachment.build(:swf_uploaded_data => params[:attachment][:attachment], :user_id => current_user.id, :project_id => params[:space_id])
#add the authorize logic explicitly here when you have the attachment model populated
authorize! :upload, #attachment
end
Let me know if that works for you.
For example if you want to allow create events for current loop only:
You use in the view
link.... if can? :create, #loop.events.new
and then in controller
skip_authorize_resource only: [:new, :create]
...
def new
#event.loop_id = #loop.id
authorize! :create, #event
end
#similar for create action